Xctestcase Optional Instance Variable

XCTestCase optional instance variable

From Flow of Test Execution
(emphasis added):

For each class, testing starts by running the class setup method. For each test method, a new instance of the class is allocated and its instance setup method executed. After that it runs the test method, and after that the instance teardown method. This sequence repeats for all the test methods in the class. After the last test method teardown in the class has been run, Xcode executes the class teardown method and moves on to the next class. This sequence repeats until all the test methods in all test classes have been run.

In your case, test_B_fooIsNotNil() is executed on a fresh instance,
for which the foo property is nil.

Common setup code can be put into the setUp() class method
or setUp() instance method, see
Understanding Setup and Teardown for Test Methods

Understanding optional global variables in swift

The reason we've set it with an exclamation mark or question mark is
because there isn't an initializer within this class

Because when every instance of a class is initialized, it has to allocate memory for its properties/instance var. So with var sut: ItemManager!, the value of sut is nil when init. Without !, ? the compiler can't allocate, init, so you have to init manually in an initializer. That is what compiler told you.

For using ! or ?.

  • ! is used when the property/var always has value after the first assigning. And after the first time it's assigned, it can't be nil later
  • ? is used when the pro/var can have value or not

Parametrized unit tests in Swift

The best way to handle parameterized testing is to use XCTContext.runActivity. This allows to create a new activity with some name that will help you identify exactly which of the iterations failed. So for your division scenario:

func testDivision() {
let testCases = [
(a: 12, b: 3, result: 4),
(a: 12, b: 2, result: 6),
(a: 12, b: 6, result: 1),
(a: 12, b: 4, result: 3),
]
for (a, b, result) in testCases {
XCTContext.runActivity(named: "Testing dividing \(a) by \(b) to get result \(result)") { activity in
XCTAssertEqual(result, a/b)
}
}
}

Note that after running the above test, case no. 1, 2 and 4 will succeed while case no. 3 will fail. You can view exactly which test activity failed and which of the assertions caused faiure in test report:

Test activity with success and failure cases

weak variable is becoming nil while writing testcase?

The warning is telling you exactly what's happening. You only have a weak pointer to a value, so nothing is going to keep your SourceViewTypeMock alive past the assignment statement. The solution is to create a strong reference. You need one that the compiler is not allowed to optimized out, so it has to be outside of this function. So you make it a property of the test case.

If it's immutable, you can do it this way:

class TheTestCase: XCTestCase {
let sourceMock = SourceViewTypeMock()

func testFundTrip() {
viewModel.source = sourceMock
viewModel.fundTrip(trip)
}
}

If it's mutable, then you probably want to make sure you recreate it in setUp:

class TheTestCase: XCTestCase {
var sourceMock: SourceViewTypeMock!

override func setUp() {
sourceMock = SourceViewTypeMock()
}

func testFundTrip() {
viewModel.source = sourceMock
viewModel.fundTrip(trip)
}
}

Swift: Will XCTest modify state? And what is the convention of testing functions that could return optional values?

  1. Yes, if you call a method that changes the state of an object/variable, then calling the XCTAssert... with this function as one of the parameters macro will result in the state-changing method getting called, resulting the concomitant state changes. No, there is nothing here that would revert the state.

    Conventionally, if state changes were involved, many of us would assign the result to a variable, and then test that variable (and possibly the state change, too):

    let returnCode = object.changeState()
    XCTAssertEqual(returnCode, ...)
    XCTAssertEqual(object.someStateProperty, ...)

    This is a stylistic matter when dealing with unit tests, but it is critical when using macros like NSAssert (because those are conditionally compiled depending upon build configuration and you don't want object states changing depending upon the build).

  2. Regarding the optionals, either forced unwrapping or optional binding is permissible, though, as always, the latter is safer if nil value is possible. Furthermore, if nil is acceptable value, you might need to perform additional tests for the various permutations (e.g. XCTAssertNil and XCTAssertNotNil).

    It depends entirely upon what precisely you're trying to test.

When are static properties initialised in testing in Swift?

As you've noticed, static properties on your test case are persistent throughout all your tests. However, XCTestCase has two sets of methods that you can override to customize this, called setUp() and tearDown(). It's somewhat confusing, since there are identically named class and instance methods for each of these; override the class methods to have something happen only once, and override the instance methods to make something happen before or after each individual test. In your case, it would probably make the most sense to override the instance method version of setUp() and have it reset your properties.

How to add helper methods to XCTestCase unit in Xcode?

Only methods that start with test will be considered tests. So, just name your helper method something that doesn't start with test.

By the way, I would not be inclined to put XCTAssert statements in your helper method. It works (the appropriate tests will fail), but in some scenarios it makes it hard to decipher which tests caused the assert in the helper method to fire.



Related Topics



Leave a reply



Submit