Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: Unit test with a void func in Swift

I want to test this method that doesn't return a value but I want to check if works fine. Can you give me some suggestions?

func login() {

            if Utility.feature.isAvailable(myFeat) {
                if self.helper.ifAlreadyRed() {
                    self.showWebViewController()
                } else {
                    let firstVC = FirstViewController()
                    self.setRootController(firstVC)
                }
            } else {
                let secondVC = SecondViewController()
                self.setRootController(secondVC)
            }
    }

so what's the best approach to apply unit test here?

like image 704
cyclingIsBetter Avatar asked Aug 18 '16 23:08

cyclingIsBetter


People also ask

Can I unit test a void method?

In conclusion, there are multiple ways to test the void method, which is dependent on the method's side-effects and what kind of test you wish to run. A unit test checks the method's functionality and can cover the void method if the side effect is stored in publicly available property.

How do you unit test a function in Swift?

Prefixing a function in an XCTestCase class with “test”, tells Xcode that the given function is a unit test. For each unit test function you will see an empty diamond shape in the gutter on the line of the function declaration. Clicking this diamond will run the specific unit test.

How do you check if a method returns void?

Using the verify() method. Whenever we mock a void method we do not expect a return value that is why we can only verify whether that method is being called or not. Features of verify(): Mockito provides us with a verify() method which lets us verify whether the mock void method is being called or not.

How do I write unit test cases in iOS Swift?

To create new unit case in iOS, go to File -> New -> File, and then select Unit Test Case Class. Doing so creates a template just like the one you got with your project. In our case, we want to name the file to correspond with the new Pokemon-related data structures we have introduced.


1 Answers

Testing side effects is one approach. But for an example like the code in question, I actually prefer a subclass-and-expect approach.

Your code has three different paths.

  1. If feature is available and already red, show web view controller.
  2. If feature is available and not already red, show first view controller.
  3. If feature is not available, show second view controller.

So assuming this login() function is part of FooViewController, one possibility is writing tests that follow this format:

func testLoginFeatureAvailableAndNotAlreadyRed() {

    class TestVC: FooViewController {
        let setRootExpectation: XCTExpectation

        init(expectation: XCTExpectation) {
            setRootExpectation = expectation
            super.init()
        }

        override func setRootController(vc: UIViewController) {
            defer { setRootExpectation.fulfill() }

            XCTAssertTrue(vc is FirstViewController)

            // TODO: Any other assertions on vc as appropriate

            // Note the lack of calling super here.  
            // Calling super would inaccurately conflate our code coverage reports
            // We're not actually asserting anything within the 
            // super implementation works as intended in this test
        }

        override func showWebViewController() {
            XCTFail("Followed wrong path.")
        }
    }

    let expectation = expectationWithDescription("Login present VC")

    let testVC = TestVC(expectation: expectation)
    testVC.loadView()
    testVC.viewDidLoad()

    // TODO: Set the state of testVC to whatever it should be
    // to expect the path we set our mock class to expect

    testVC.login()

    waitForExpectationsWithTimeout(0, handler: nil)

}
like image 118
nhgrif Avatar answered Oct 07 '22 13:10

nhgrif