Unit Test case fails when whole Test Suite is executed - ios

I am writing the Unit test cases for my sqlite database class. I have five public API in that class.
My test cases goes something like below:
+ (void)setUp { // Note, this is class method and hence called only once during start of this test suite.
// Code to delete the existing sqlite DB file.
}
- (void)testDBManagerSingletonInstance {
DBManager *dbMgr = [DBManager getSharedInstance];
DBManager *dbMgr1 = [[DBManager alloc] init];
XCTAssertEqualObjects(dbMgr, dbMgr1);
}
- (void)testSaveAndDeleteNicknameAPI {
// Multiple Assert statements in this test.
}
- (void)testAllAccountStatusAPIs {
// Multiple Assert statements in this test.
}
Each of the single unit test is executed without any errors. But it fails when whole test suite is executed.
Probably, I know the Root Cause for failing. It is because when entire test suite is executed then all test runs in parallel and there is simultaneous update-delete happens in the database. Hence, when all unit tests runs it will fail.
But I don't know how can I fix that, because this is not Async, and hence I cannot use XCExpectation class.
Need assistance to resolve & understand the problem.

Tests based on XCTests don't run in parallel - they are run sequentially. To quote the docs :
Tests execute synchronously because each test is invoked independently one after another.
Since you've shown very little code, it's hard to say what is the real problem. It is very likely that you were close with your assumption - you should either improve your setUp (maybe switch to instance version from class version) and tearDown methods or introduce mocks, and perform your tests on a mocked database if possible.

You shouldn't work with singletons in a codebase you want to test. I think that your code uses the sharedSingleton instance of DBManager internally. Each unitest will change the internal state of that instance, all following unitests are therefore corrupted. You need to reset all changes after each test case in teardown.
But my suggestion is to avoid singletons in your base code by dependency injection. When creating an instance of your class inject the singleton instance of your DBManager. That makes unit testing easier. If you inject a protocol instead of an object you may even test your code with a protocol fake implementation.

Related

How to use tests in Xcode (iOS application)

In every new project I see the file with the content (and this file belongs to different target ProjectNameTests):
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
XCTAssert(YES, #"Pass");
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
1) How to use this file?
2) How can I test my application with this file? Why it's better then just launching the application and testing it or then to write test code directly in AppDelegate (when I need to test the responce from server for instance)?
These are called Unit Tests and you can test your components, like classes and functions, with them. You write a Test and if you change something on your classes, the test will show you if the class still works as expected.
For an example: http://www.preeminent.org/steve/iOSTutorials/XCTest/
You should also read a bit about test driven development, it is a nice way of developing and mandatory for most companies.
As a down side on XCode UnitTests i have to tell you that you can't use operations on files within them.
1) To use that file, you replace the testExample and testPerformanceExample with your own methods that begin with test. For example, if you want to test that your Foo class object returns true for isFoo:
- (void)testFooIsFoo() {
Foo f = [Foo new];
XCTAssertTrue([f isFoo], "Foo object should return true for isFoo");
}
2) Why is this better than manual testing? You can write smaller tests for parts that might be more time consuming to reach in the app. It also allows you to test things in isolation. So, rather than test that the network stack works, these kinds of tests are good for testing that you handle data correctly and so on.
Good testing requires a mix of unit testing (which is what this is) and manual testing.
Apple's documentation is light on the why and what you should unit test. But this is a good article from objc.io about testing this way and how to do it with XCTest.
Apple provide a nice documentation. But if you want to see real code, I have a github project that implements tests.
The main purpose ox XCTests is that you can launch tests from Xcode directly without building and running the program. Xcode provide a nice interface to do that.

iOS and XCode: understanding automatic testing

I have created a test project and noticed that XCode generates some test class named: YourProjectName-ProjectTests
This is how it looks like:
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
XCTAssert(YES, #"Pass");
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
Would anyone be able to explain me how to use these automated testing methods? Is there an official documentation on this?
Are those test meant to be used as UI testing or as app code testing? Or both?
You an perform UI tests through XCTest but it's designed for unit testing. Instruments has UI Automation which is designed for UI testing.
Opening up XCTestAssertions.h will give you a pretty good reference for what's included in XCTest. Generally all the assertions follow a similar pattern:
XCTAssertSomething(somethingBeingTested, #"A message to display if the test fails");
Hitting ⌘ 5 will bring up the test navigator which lets you run all of your tests, all of your failed tests, or individual tests. You can also run a test by clicking on the diamond shape to the left of the method name in the editor.
Here are a few tips I've come across when unit testing with XCTest:
The last argument in assertions is optional but in some cases it's useful to describe the behaviour you're looking for.
Tests are not run in any specific order, but your tests shouldn't rely on each other anyway.
Mock objects let you test far, far more than basic assertions. I like OCMock.
You can use instruments on your tests for debugging.
Finally, if you have access to another machine you can set up OSX Server to automatically run your tests daily or on every commit and notify you if any of the tests fail.
This is how Unit Testing is implemented in Xcode.
The setUp and TearDown methods are to prepare any mock data necessary to test a unit (which is select part of code).
The two test methods there are just an example. Usually as an author of the unit of code, you know well what the unit supposed to do and what it should not.
Using test methods you test how the assumptions and expectations are satisfied by the unit. The convention is to have a separate test method for each assumption/expectation of a behaviour of the unit.
For example given class that handles strings that has a method to to make all strings CAPS, you would test that passing any random nonCaps string would still return ALL CAPS. An putting none truing as a parameter would return nil or error.
So basically you test your units to behave as expected.
There's a whole theory behind Unit Testing which is out of scope of this thread. Just Google it.

DUnit: 'Global' SetUp and TearDown

In DUnit, SetUp and TearDown are called before (and after, respectively) each test method is executed.
In SetUp, I create an object that loads data from a file. This is slow, especially if I have many tests.
Is there any way to call SetUp once, before executing ALL tests (and obviously the same for TearDown)?
From the documentation:
TTestSetup
TTestSetup can be used when you wish to set up state exactly once for
a test case class (the SetUp and TearDown methods are called once for
each test method). For example, if you were writing a suite of tests
to exercise some database code, you might subclass TTestSetup and use
it to open and close the database before executing the suite.
An an example how to use TTestSetup

Verify method call with OCMockito

I have these two methods in a ClassA
-(IBAction)onSubmit;
-(void)validateName:(NSString*)name;
#Implementation
- (IBAction)onSubmit {
[self validateName:self.textfield.text];
}
-(void)validateName:(NSString*)name{
// do something
}
My test look like the below:
//given
ClassA *classA = mock([ClassA class]);
classA.textfield.text = #"Foo";
// when
[classA onSubmit];
[verify(classA) validateName:#"Foo"];
But that doesn't work, I keep getting:
Expected 1 matching invocation, but received 0
How can I write a test that verifies that validateName is executed, when onSubmit is being called.
Proper unit tests test internal state and external behavior. Your unit tests are testing whether your code does something, not how it does something. The state verification tells you that your intended results are achieved, while the behavior verification tells you that your collaborating objects correctly interface with your system under test. This allows you to do wonderful things like refactor.
A test of internal state goes like this:
Given an initial state, if the system under test does something, then
the resultant state should be this.
A test of external behavior goes like this:
If the system under test does something, then another unit should do something else.
The first sort of tests are accomplished with standard assertions (assertThat() calls in the case of OCHamcrest). The second sort of tests are (properly) accomplished with verification of test doubles (verify() calls in the case of OCMockito).
It wouldn’t make any sense to mock the system under test. If you find it necessary to test the internal behavior (i.e. the particular methods called by the system under test), then you need to map those behaviors to states. In your case this would mean that ClassA implements a flag such as BOOL nameValidated (preferably with the getter isNameValidated) or a variable such as NSString *validatedName.

how to troubleshoot intermittent junit test failures?

I am dealing with a case where my tests pass or fail based on the order of declaration. This of-course points to not properly isolated tests. But I am stumped about how to go about finding the issue.
The thing is my junit tests derive from a class that is belongs to a testing framework built on junit and has some dependency injection container. The container gets reset for every test by the base class setup and so there are no lingering objects at least in the container since the container itself is new. So I am leaning toward the following scenario.
test1 indirectly causes some classA which sets up classA.somestaticMember to xyz value. test obj does not maintain any references to classA directly- but classA is still loaded by vm with a value xyz when test1 ends.
test2 access classA and trips up on somestaticmember having xyz value.
The problem is a) I dont know if this is indeed the case- how do I go about finding that ? I cannot seem to find a reference to a static var in the code...
b) is there a way to tell junit to dump all its loaded classes and do it afresh for every test method ?
You can declare a method with #Before, like
#Before public void init()
{
// set up stuff
}
and JUnit will run it before each test. You can use that to set up a "fixture" (a known set of fresh objects, data, etc that your tests will work with independently of each other).
There's also an #After, that you can use to do any cleanup required after each test. You don't normally need to do this, as Java will clean up any objects you used, but it could be useful for restoring outside objects (stuff you don't create and control) to a known state.
(Note, though: if you're relying on outside objects in order to do your tests, what you have isn't a unit test anymore. You can't really say whether a failure is due to your code or the outside object, and that's one of the purposes of unit tests.)

Resources