# readLine() with macOS



Recently I tried to test the model of a new application, with user interaction in the console or on the terminal. I called the readLine() function in a macOS project.

In xcode, create a new project macOS, choose **Command Line Tool**.
Your project contain only one file *main.swift*, without storyboard, info.plist, SceneDelegate, Assets.xcassets.

You can now create other *swift file* to implement classes, and simulate your application by asking user interaction.

For example, to ask user give a name to his first player,

	class Player {
		var playerName: String
		var fighters: [Fighter]
			init(playerName: String, fighters: [Fighter]) {
					self.playerName = playerName
					self.fighters = fighters
			}
		func setPlayerName(at index: Int) {
			repeat {
				print("\n")
				print("give a PLAYER NAME for TEAM \(index + 1): ")
					let name = readLine()?.uppercased()
					playerName = name ?? "Rambo"
			} while playerName.isEmpty
			print("the player name of team \(index + 1) is \(playerName) !")
			print("\n")
		}
	}
	
When you launch your application, you've got the sentence *give a name for player 1* in the  Xcode console.
 If you answer *"john"* and confirm, you've got,
````
	the player name of team 1 is john !
````

You can call this function in an other class.

	  var nameFighter = player2.setFighterName()

---------

To input a *Int* type answer, use,

      Int(readLine()!)

-------

The application can be run in the Xcode console or in the Terminal.
In **Edit Scheme**, select *Run*, then the *Options* tab, at the bottom of the list you can choose to use the Xcode console, or the Terminal.

--------

### Unit tests are  welcome.

With Apple's **XCTest** framework.

To find out what needs to be tested, select the model file to be tested, then **Navigate/Jump to Generated Interface** (matches non-private variables and func)

1 - To test you application, add a new target, and choose  **Unit Testing Bundle** template.

Give a name to this new file (*application name + tests*).

	exampleTests

Your new target is visible in the targets list, and a new folder has been created in the browser.
This target can be created when the project is created, by checking the box *Include Unit Tests*.

The test target can also be created from the sixth tab (**Test navigator**) (diamond with a -) of the browser.
By clicking on the + at the bottom of the window, a new test target (unit or UI), or a new class, can be created.

2 - Delete the *ApplicationNameTests.swift* file created by default.

Create a new file *Unit Test Case Class*, name it with the name of the file to be tested + TestCase, 

	exampleTestCase 
	
Create it by checking that the target is the one of the Tests.
If there is a "Would you like to configure an Objective-C bridging header?" alert, choose "Don't Create".

*WARNING*: for each file in the application, the *Target Membership* must be checked in the *Identity and Type* inspector 

3 - To create a test, create a func with the word test before the func name. Example: 

	func testExemple() {
		XCTAssert(true)
	}
	
The application is not in the same module as the tests. 

And by default, the *access control* is set to internal (access in the same module). 

So to make the app module accessible in the test module, we can make all classes *public* (not safe), or precede the app import with the @testable attribute.

	@testable import nomApplication

In general, a test is broken down into three parts, following the **"AAA" ** pattern, which stands for "Arrange, Act, Assert 

 - **Arrange** : Define the objects and variables necessary for the proper functioning of the test (initialize the variables, initialize the objects to be passed as parameters of the method to be tested)
 - **Act** : Execute the action you wish to test
 - **Assert** : Check that the result is as expected

4 - To test functions with a readLine(), create a mock to override the function and simulate a user response.

-------------------
### BDD

We can do our first test using a technique to name it: **Behaviour Driven Development** 
-   _**Given**_ : Starting situation (étant donné que....)
    
-   _**When**_ : Action
    
-   _**Then**_ : Arrival situation

---------------------
### COVERAGE

To evaluate test coverage, install *code coverage*.

Select the name of the application, at the top left of the simulator model, then choose *Edit Scheme*. 
In the popup, select *Test*, then in the *options* tab, check *Gather coverage all section (target in iOS)*, and *close*.

Now, after running the tests (cmd+u), in the **Report Navigator** (9th tab), by clicking on Coverage, you get the percentage coverage of the tests and locate.

---------------------
### Thanks

For **more informations** including ViewController tests and UITests, see the excellent tutorials :
 - by David Piper [iOS Unit Testing and UI Testing Tutorial](https://www.raywenderlich.com/21020457-ios-unit-testing-and-ui-testing-tutorial)
 - And one in French by Ilan Benichou [Des tests unitaires en Swift avec Xcode](https://blog.eleven-labs.com/fr/test-unitaire-swift-xcode/)
