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 :