Unexpected behaviour of XCTestCase -- create different instance to run test methods

StackOverflow https://stackoverflow.com/questions/21641530

  •  08-10-2022
  •  | 
  •  

سؤال

I write unit test case with XCTestCase, and initialize variables in -setUp as following:

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _myPath = @"Path";
    });
}

But when I try to use myPath in test cases, it only works in the first one, and the "myPath" would be in nil in subsequent cases.

So I set break point in -setUp to see what's happen. And I found that it create new instances for each methods!!

To double check it, I create a new project and test target to log testcase address as following:

@implementation fooTestTests
- (void)setUp
{
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    NSLog(@"<fooTestTests: %p>", self);
}

- (void)tearDown
{
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

- (void)testExample
{
    XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}

- (void)testExample2
{
    XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}
@end

And the result is :

fooTest[846:303] <fooTestTests: 0x1005ab750>
fooTest[846:303] <fooTestTests: 0x1005ab7f0>

Since the XCTestCase was designed as a object have one or more test method, it should not create different instance for each method.

In such situation, I don't know where to setup my test environment. Even though write setup code in -init, it still create new instance and call -init many times. Currently, I have only a few unit test, but when the number of tests grows, and the setup procedure becomes more complex, it would be a problem. Could anyone give me a suggestion?

Add Question Summary:

If I have 2 test methods in one testcase class, the behaviour would be:

  1. Instantiate new testcase as object 1
  2. -setUp
  3. test 1
  4. -tearDown
  5. Instanitate new testcase as object 2
  6. -setUp
  7. test 2
  8. -tearDown

Why it needs step 5?

The Answer

The answer provided by Jon Reid

More information:

هل كانت مفيدة؟

المحلول

To run a single test, this is the regular pattern of xUnit test frameworks, including XCTest:

  1. Instantiate new test object
  2. Invoke -setUp
  3. Invoke test method
  4. Invoke -tearDown

That concludes a single test. The test object itself will be destroyed at some later time outside of our control.

So don't use -init or -dealloc with test objects. Instead use -setUp and -tearDown which are guaranteed to be called before, and after, each test. But each test does operate on a brand-new instance of the object. This helps keep tests isolated.

So get rid of your dispatch_once.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top