--- | |
layout: default | |
title: What's new in OCMock 3 | |
tags: [] | |
status: publish | |
type: page | |
published: true | |
comments: false | |
--- | |
<h1>{{ page.title }}</h1> | |
<p>OCMock 3 is almost completely backwards compatible with previous versions of OCMock while introducing the following changes: | |
<ol> | |
<li>Modern syntax | |
<li>Verify after running | |
<li>Apache 2 license | |
</ol> | |
<p>This page describes the changes. For a description of all the features please consult the <a href="{{ site.baseurl }}/reference">reference page</a>. | |
<h2 class="toc numbered">Modern syntax</h2> | |
<p>In addition to the existing syntax OCMock 3 introduces a new “modern” syntax that uses macros and round brackets. We believe that there are several benefits: | |
<ul> | |
<li>Better error reporting: failures are reported with location in Xcode/AppCode | |
<li>Blends in with other testing frameworks: XCT and other frameworks also use a function-like syntax | |
<li>Clearer distinction between mock setup and method calls | |
</ul> | |
<p>Examples of the new syntax: | |
{% highlight objc %} | |
id mock = OCMClassMock([NSString class]); | |
OCMStub([mock uppercaseString]).andReturn(@"TEST_STRING"); | |
id partial = OCMPartialMock(anObject); | |
OCMExpect([partial exampleMethod]).andForwardToRealObject().andReturn(@"TEST_STRING"); | |
{% endhighlight objc %} | |
<p>These are equivalent to the following code in OCMock 2: | |
{% highlight objc %} | |
id mock = [OCMockObject niceMockForClass:[NSString class]]; | |
[[[mock stub] andReturn:@"TEST_STRING"] uppercaseString]; | |
id partial = [OCMockObject partialMockForObject:anObject]; | |
[[[[partial expect] andForwardToRealObject] andReturn:@"TEST_STRING"] exampleMethod]; | |
{% endhighlight objc %} | |
<p>The following “functions” are available. (They are not implemented as C functions.) | |
<p>Creating mock objects: | |
<ul> | |
<li><b>OCMClassMock(cls)</b>: creates a new nice class mock object | |
<li><b>OCMStrictClassMock(cls)</b>: creates a class mock object | |
<li><b>OCMProtocolMock(protocol)</b>: creates a nice protocol mock object | |
<li><b>OCMStrictProtocolMock(protocol)</b>: creates a protocol mock object | |
<li><b>OCMPartialMock(obj)</b>: creates a partial mock for the object | |
<li><b>OCMObserverMock()</b>: creates an observer mock object | |
</ul> | |
<p>Creating stubs and expectations: | |
<ul> | |
<li><b>OCMStub(invocation)</b>: creates a stub for a class or instance method invocation | |
<li><b>OCMExpect(invocation)</b>: creates an expectation for a class or instance method invocation | |
<li><b>OCMStub(ClassMethod(invocation))</b>: creates a stub for the class method invocation | |
<li><b>OCMExpect(ClassMethod(invocation))</b>: creates an expectation for the class method invocation | |
</ul> | |
<p>The use of <code>ClassMethod</code> is only necessary if a class contains a class and instance method with the same name and the class method is to be mocked. In all other cases OCMock can determine automatically whether a class or instance method is targeted. | |
<p>Setting up stubs and expectations: | |
<ul> | |
<li><b>andReturn(something)</b>: tells a stub/expecation to return an object or a value | |
<li><b>andPost(aNotification)</b>: posts a notification | |
<li><b>andThrow(anException)</b>: throws an exception | |
<li><b>andCall(anObject, aSelector)</b>: calls a selector on an object | |
<li><b>andDo(aBlock)</b>: calls a block | |
<li><b>andForwardToRealObject()</b>: forwards method to real object (partial mocks and class methods) | |
</ul> | |
<p>Verification: | |
<ul> | |
<li><b>OCMVerifyAll(mock)</b>: verifies all expectations on the mock | |
<li><b>OCMVerifyAllWithDelay(mock, delay)</b>: verifies all expectations on the mock, waiting for the expectations | |
</ul> | |
<p>It is possible to mix and match the new syntax with the traditional method-based syntax. | |
<h2 class="numbered">Verify after running</h2> | |
<p>Most of the original mock frameworks follow the <i>expect-run-verify</i> approach. OCMock is one of these frameworks. Over the years, as we all gathered more experience, it became clear that this approach has its problems, and the <a href="https://github.com/mockito/mockito">Mockito</a> framework pioneered a new approach: <i>verify-after-running</i>. There are no expectations, all mocks are <i>nice</i>, i.e. they do not complain when an unexpected method is called, and verification of specific calls is done after the code under test is run. | |
<p>OCMock 3 supports this approach to testing in addition to the traditional approach. With the modern syntax the default is to create nice mocks. On a mock that has no expectations set the <b>verify</b> method and the <b>OCMVerify</b> function allow verification after the fact: | |
{% highlight objc %} | |
id mock = OCMClassMock([NSString class]); | |
/* code under test, do something with the mock */ | |
OCMVerify([mock uppercaseString]); | |
id mock = [OCMockObject niceMockForClass:[NSString class]]; | |
/* code under test, do something with the mock */ | |
[[mock verify] uppercaseString]; | |
{% endhighlight objc %} | |
<p>In this example, the code under test can call any methods on the mock object. No checking is done. Only when <b>OCMVerify()</b> or the <b>verify</b> method are called, the mock verifies whether the respective invocation has occured and, if not, reports an error. | |
<h2 class="numbered">Apache 2 license</h2> | |
<p>It has become clear that a non-standard BSD-style license with attribution clause is not ideal. I am not a lawyer but the Apache 2 license seems quite close in spirit to the existing license, and it has the benefit of being a widely used standard open source license. For that reason OCMock 3 has been released under the Apache 2 license. If you are a previous contributor and you have concerns please do get in touch. | |