Verify method call with OCMockito - ios

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.

Related

Unit Test case fails when whole Test Suite is executed

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.

in unit test, set mocked value to an argument (pass-by-reference)

I have a method:
-(void)startTaskForResult:(long long*)result {
...
}
The function I want to unit test invoke above function:
-(void)doWork {
long long result = 0;
[self startTaskForResult:&result];
}
I am using OCMock library to do unit tests. In my test case, I want to set the result argument to an mocked value e.g. 100 without care about the actual implementation of -(void)startTaskForResult:(long long*)result.
I tried the following way:
-(void)testDoWork{
// try to set 100 to argument 'result'
OCMStub([classToTest startTaskForResult:[OCMArg setToValue:OCMOCK_VALUE((long long){100})]]);
// run the function, but it doesn't use mocked value 100 for argument 'result'
[classToTest doWork];
...
}
But, when I run my test, it does't use the mocked value 100 for argument result. What is the right way to set mocked value to argument in my case then?
Few points to answer your question:
Code for your problem:
- (void)testDoWork
{
id mock = OCMPartialMock(classToTest)
OCMStub([mock startTaskForResult:[OCMArg setToValue:OCMOCK_VALUE((long long){100})]]).andForwardToRealObject;
// set your expectation here
[classToTest doWork];
}
To solve your particular problem:
Your object should be partial mock
Your method should be stubbed (you did it)
Your stub should be forwarded to real object (i assume you need method startTaskForResult: implementation to be called)
However, you face the problems because you are using wrong approach to test;
There're 3 most common strategies to write unit tests:
Arrange-Act-Assert used to test methods
Given-When-Then used to test functions
Setup-Record-Verify used to test side effects. This usually requires mocking.
So:
If you want to test that startTaskForResult: returns particular value - you should call just that and expect return value (not your case, method return type is void)
If method changes the state of object - you should expect that state change, like property value or so
If calling of doWork has a side effect of calling startTaskForResult:, you should stub it and expect it's call, almost like i've written in code above. However (!!!), however you shouldn't expect things like this. This is not a kind of behaviour that has much sense to test, because it's internal class implementation details. One possible case, when both methods are public and it's explicitly stated in class contract, that one method should call another with some preliminary setup. In this case you expect method call with some state / arguments.
To have your application code testable, you require continuously refactoring your code. Some code is untestable, it's probably better to adopt application code rather then try to cover it with tests anyway. You lose the initial goal of tests - refactoring safety and low cost of making changes.

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.

Need to mock one service method only in an integration test

I am writing grails integration tests which call out to a controller which call a service which calls another service which calls another service.
Controller -> ServiceA.method1() -> ServiceB.method2() -> ServiceC.method3()
the last method in the last service to be called (ServiceC.method3()) makes a call to the outside world (another JVM) and returns a result, which I want to mock out for my integration test. So I am still testing the chain up to and back from that particular service method.
I was reading up on mocking in grails but it seems that it is only possible in unit testing.
Any tips how to progress this one?
Use the metaClass to override a method's functionality. I do this all the time in my integration tests as my way to mock.
So in your test method do something like this (note that the method arg types must match exactly with the real method):
controller.serviceA.serviceB.serviceC.metaClass.method3 = { Args args ->
// do whatever you want here, set flags to indicate method called,
// assert args, declare return types, etc
// return 'mocked' result
}
Make sure in your integration test tear down method you reset the metaClass of this service otherwise all your other int tests will have the same definition:
controller.serviceA.serviceB.serviceC.metaClass = null
I was reading up on mocking in grails but it seems that it is only
possible in unit testing.
That's certainly not true.
You could use all ways of mocking that are available in Groovy in both unit and integration tests.
With mocking using Map coercion, it can be this easy:
controller.serviceA.serviceB.serviceC = [method3: {return 'MockValue'}] as ServiceC

Resources