Giter Site home page Giter Site logo

jonreid / ocmockito Goto Github PK

View Code? Open in Web Editor NEW
991.0 24.0 117.0 5.43 MB

Mockito for Objective-C: creation, verification and stubbing of mock objects

License: MIT License

Objective-C 97.55% Ruby 0.67% Shell 1.32% Swift 0.46%
objective-c mockito xctest mocking-framework testing mocking

ocmockito's Introduction

mockito

OCMockito

Build Status Coverage Status Swift Package Index Platform Compatibility Carthage compatible CocoaPods Version Mastodon Follow

OCMockito is an Objective-C implementation of Mockito, supporting creation, verification and stubbing of mock objects.

Key differences from other mocking frameworks:

  • Mock objects are always "nice," recording their calls instead of throwing exceptions about unspecified invocations. This makes tests less fragile.

  • No expect-run-verify, making tests more readable. Mock objects record their calls, then you verify the methods you want.

  • Verification failures are reported as unit test failures, identifying specific lines instead of throwing exceptions. This makes it easier to identify failures.

Contents

Let's verify some behavior!

// mock creation
NSMutableArray *mockArray = mock([NSMutableArray class]);

// using mock object
[mockArray addObject:@"one"];
[mockArray removeAllObjects];

// verification
[verify(mockArray) addObject:@"one"];
[verify(mockArray) removeAllObjects];

Once created, the mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.

(If Xcode complains about multiple methods with the same name, cast verify to the mocked class.)

How about some stubbing?

// mock creation
NSArray *mockArray = mock([NSArray class]);

// stubbing
[given([mockArray objectAtIndex:0]) willReturn:@"first"];
[given([mockArray objectAtIndex:1]) willThrow:[NSException exceptionWithName:@"name"
                                                                      reason:@"reason"
                                                                    userInfo:nil]];

// following prints "first"
NSLog(@"%@", [mockArray objectAtIndex:0]);

// follows throws exception
NSLog(@"%@", [mockArray objectAtIndex:1]);

// following prints "(null)" because objectAtIndex:999 was not stubbed
NSLog(@"%@", [mockArray objectAtIndex:999]);

How do you mock a class object?

__strong Class mockStringClass = mockClass([NSString class]);

(In the iOS 64-bit runtime, Class objects aren't strong by default. Either make it explicitly strong as shown above, or use id instead.)

How do you mock a protocol?

id <MyDelegate> delegate = mockProtocol(@protocol(MyDelegate));

Or, if you don't want it to contain any optional methods:

id <MyDelegate> delegate = mockProtocolWithoutOptionals(@protocol(MyDelegate));

How do you mock an object that also implements a protocol?

UIViewController <CustomProtocol> *controller =
    mockObjectAndProtocol([UIViewController class], @protocol(CustomProtocol));

How do you stub methods that return primitives?

To stub methods that return primitive scalars, box the scalars into NSValues:

[given([mockArray count]) willReturn:@3];

How do you stub methods that return structs?

Use willReturnStruct:objCType: passing a pointer to your structure and its type from the Objective-C @encode() compiler directive:

SomeStruct aStruct = {...};
[given([mockObject methodReturningStruct]) willReturnStruct:&aStruct
                                                   objCType:@encode(SomeStruct)];

How do you stub a property so that KVO works?

Use stubProperty(mock, property, stubbedValue). For example, say you have a mock object named mockEmployee. It has a property firstName. You want to stub it to return the value "FIRST-NAME":

stubProperty(mockEmployee, firstName, @"FIRST-NAME");

This stubs the firstName property, valueForKey: and valueForKeyPath:.

Argument matchers

OCMockito verifies argument values by testing for equality. But when extra flexibility is required, you can specify OCHamcrest matchers.

// mock creation
NSMutableArray *mockArray = mock([NSMutableArray class]);

// using mock object
[mockArray removeObject:@"This is a test"];

// verification
[verify(mockArray) removeObject:startsWith(@"This is")];

OCHamcrest matchers can be specified as arguments for both verification and stubbing.

Typed arguments will issue a warning that the matcher is the wrong type. Just cast the matcher to id.

How do you specify matchers for non-object arguments?

To stub a method that takes a non-object argument but specify a matcher, invoke the method with a dummy argument, then call -withMatcher:forArgument:

[[given([mockArray objectAtIndex:0]) withMatcher:anything() forArgument:0]
 willReturn:@"foo"];

This is particularly useful for ignoring NSError ** parameters: pass in NULL, but override it with an anything() matcher.

Use the shortcut -withMatcher: to specify a matcher for a single argument:

[[given([mockArray objectAtIndex:0]) withMatcher:anything()]
 willReturn:@"foo"];

These methods are also available to specify matchers for verification. Just call them after verify(…) but before the invocation you want to verify:

[[verify(mockArray) withMatcher:greaterThan(@5])] removeObjectAtIndex:0];

Verifying exact number of invocations / at least x / never

// using mock
[mockArray addObject:@"once"];

[mockArray addObject:@"twice"];
[mockArray addObject:@"twice"];

// the following two verifications work exactly the same
[verify(mockArray) addObject:@"once"];
[verifyCount(mockArray, times(1)) addObject:@"once"];

// verify exact number of invocations
[verifyCount(mockArray, times(2)) addObject:@"twice"];
[verifyCount(mockArray, times(3)) addObject:@"three times"];

// verify using never(), which is an alias for times(0)
[verifyCount(mockArray, never()) addObject:@"never happened"];

// verify using atLeast()/atMost()
[verifyCount(mockArray, atLeastOnce()) addObject:@"at least once"];
[verifyCount(mockArray, atLeast(2)) addObject:@"at least twice"];
[verifyCount(mockArray, atMost(5)) addObject:@"at most five times"];

Capturing arguments for further assertions

OCMockito verifies argument values using OCHamcrest matchers; non-matcher arguments are implicitly wrapped in the equalTo matcher to test for equality. In some situations though, it's helpful to capture an argument so you can send it another message.

OCHamcrest provides a special matcher for this purpose: HCArgumentCaptor. Specify it as an argument, then query it with either the value or allValues properties.

For example, you may want to send the captured argument a message to query its state:

HCArgumentCaptor *argument = [[HCArgumentCaptor alloc] init];
[verify(mockObject) doSomething:(id)argument];
assertThat([argument.value nameAtIndex:0], is(@"Jon"));

Capturing arguments is especially handy for block arguments. Capture the argument, cast it to the block type, then invoke the block directly to simulate the ways it will be called by production code:

HCArgumentCaptor *argument = [[HCArgumentCaptor alloc] init];
[verify(mockArray) sortUsingComparator:(id)argument];
NSComparator block = argument.value;
assertThat(@(block(@"a", @"z")), is(@(NSOrderedAscending)));

Stubbing consecutive calls

[[given([mockObject someMethod:@"some arg"])
    willThrow:[NSException exceptionWithName:@"name" reason:@"reason" userInfo:nil]]
    willReturn:@"foo"];

// First call: throws exception
[mockObject someMethod:@"some arg"];

// Second call: prints "foo"
NSLog(@"%@", [mockObject someMethod:@"some arg"]);

// Any consecutive call: prints "foo" as well. (Last stubbing wins.)
NSLog(@"%@", [mockObject someMethod:@"some arg"]);

Stubbing with blocks

We recommend using simple stubbing with willReturn: or willThrow: only. But willDo: using a block can sometimes be helpful. The block can easily access invocation arguments by calling mkt_arguments from NSInvocation+OCMockito.h. Whatever the block returns will be used as the stubbed return value.

[given([mockObject someMethod:anything()]) willDo:^id (NSInvocation *invocation){
    NSArray *args = [invocation mkt_arguments];
    return @([args[0] intValue] * 2);
}];

// Following prints 4
NSLog(@"%@", [mockObject someMethod:@2]);

You can stub a void method with a block by using givenVoid instead of given.

Problems with dealloc

Use stopMocking(…) if a -dealloc of your System Under Test is trying to message an object that is mocked. It disables message handling on the mock and frees its retained arguments. This prevents retain cycles and crashes during test clean-up. See StopMockingTests.m for an example.

How do you mock a singleton?

The short answer is: Don't. Instead of your class deciding who it's going to talk to, inject those dependencies.

The longer answer is: Well. Legacy code. Call stubSingleton on a mock class object, specifying the name of the factory method.

__strong Class mockUserDefaultsClass = mockClass([NSUserDefaults class]);
NSUserDefaults* mockDefaults = mock([NSUserDefaults class]);

stubSingleton(mockUserDefaultsClass, standardUserDefaults);
[given([NSUserDefaults standardUserDefaults]) willReturn:mockDefaults];

Beware! This uses swizzling. You need to make sure the mock class object gets deallocated so that the swizzling is undone.

In the example above, mockUserDefaultsClass will go out scope and be destroyed. But what if you kept it in the test fixture, as an ivar or a property? According to XCTest's design, it won't be implicitly destroyed. You need to explicitly set it to nil in -tearDown, or the swizzling will bleed over to your other tests, compromising their integrity.

If you need more control over when the swizzling is undone, call stopMocking(…) on the mock class.

How do I add OCMockito to my project?

The Examples folder shows projects ready to use OCMockito via Swift Package Manager, CocoaPods, or through the prebuilt framework.

Swift Package Manager

Include an OCMockito package in your Package.swift manifest's array of dependencies:

dependencies: [
    .package(
        url: "https://github.com/jonreid/OCMockito",
        .upToNextMajor(from: "7.0.0")
    ),
],

snippet source | anchor

Then add OCMockito to the dependencies of your .testTarget:

.testTarget(
    name: "ExampleTests",
    dependencies: [
        "Example",
        "OCMockito",
    ]
),

snippet source | anchor

CocoaPods

If you want to add OCMockito using Cocoapods then add the following dependency to your Podfile. Most people will want OCMockito in their test targets, and not include any pods from their main targets:

target 'MyTests' do
  inherit! :search_paths
  use_frameworks!
  pod 'OCMockito', '~> 7.0'
end

Carthage

Add the following to your Cartfile:

github "jonreid/OCMockito" ~> 7.0

Then drag the the built frameworks (both OCHamcrest and OCMockito) from the appropriate Carthage/Build directory into your project, but with "Copy items into destination group's folder" disabled.

Prebuilt Framework

A prebuilt binary is available on GitHub for OCMockito. You will also need OCHamcrest. The binary is packaged as OCMockito.xcframework, containing these architectures:

  • macOS
  • Mac Catalyst
  • iOS device
  • iOS simulator
  • tvOS device
  • tvOS simulator
  • watchOS device
  • watchOS simulator

Drag the XCFramework into your project.

Build Your Own

If you want to build OCMockito yourself, clone the repo, then

$ cd Source
$ ./MakeDistribution.sh

Author

Jon Reid is the author of iOS Unit Testing by Example. His website is Quality Coding.

ocmockito's People

Contributors

actions-user avatar anagromataf avatar cerihughes avatar codiophile avatar dalef84 avatar dependabot[bot] avatar divinedominion avatar igorsales avatar jasonlagaac avatar jonreid avatar klundberg avatar kmcbride avatar lysannschlegel avatar mateuszszklarek avatar nschum avatar renep avatar sergiou87 avatar statusreport avatar stigi avatar stuclift avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ocmockito's Issues

Verifying that class factory method calls the corresponding `init` method

Hi! I want to test that my class factory method +lessonWithName: calls the corresponding -initWithName: instance method. That's my test code:

// given
Class mockLessonModel = mockClass([LessonModel class]);

// when
[mockLessonModel lessonWithName:@"001_testing"];

// then
(void)[[verify(mockLessonModel) alloc] initWithName:@"001_testing"];

But it always fails with error Expected 1 matching invocation, but received 0.
What's the correct way to do this kind of checks?

P.S.
Here's my LessonModel code in case I'm missing something obvious:

@implementation LessonModel
+ (instancetype) lessonWithName:(NSString *)name
{
    return [[self alloc] initWithName:name];
}

- (id) initWithName:(NSString *)name
{
    return [super init];
}
@end

Crash related to KVO in 1.0.0

I'm trying to mock an object that is passed to my SUT. When passed, tha SUT registers the mock as observer for some properties. In SUT dealloc, it calls removeObserver on the mock. This was working just fine with OCMockito 0.23, but when updating to 1.0.0, this test makes OCMockito to get trapped in [HCIsEqual .cxx_destruct]. Debugging a little bit, lead me to MKTInvocationContainer method:

  • (void)setInvocationForPotentialStubbing:(NSInvocation *)invocation

in which the invocation is told to retain its arguments. Could be a retain cycle?

Furthermore, I've been doing some research and I found several SO answers stating the incompatibility between NSProxy and KVO:

http://stackoverflow.com/questions/9054970/nsproxy-and-key-value-observing

http://stackoverflow.com/a/17457155/2824409

However, I wonder why this was working with OCMockito 0.23 and not now. Any idea?

The solution in my case is to replace the mock with a real object. This works fine, but it is painful to build a whole object for a test suite that barely uses it.

At any case, if KVO is not supported with mocks, I believe this should be documented, and properly handled.

[EDIT]

I found a workaround for this problem.

We are using a custom block based KVO infrastructure, similar to the described here: http://www.mikeash.com/pyblog/key-value-observing-done-right.html. Now, SUT is registering the mock for KVO, passing self inside a block. I believe self is beign retained somewhere, but it shouldn't be, since it is weakified before the block...

Using the default kvo framework provided by Apple seems to fix this problem. However, I'm still worried about the underlying problem. What changed in OCMockito that makes this fail now?

Anyway, sorry for the trouble and thank you very much.

Infrastructure issue

Could you mention somewhere, maybe readme, how to start with the project after checkout. If it is possible to remove any manual step it will be even more awesome

I have next major questions:

  1. How to build project with Xcode or command line. I have currently build error - requirement to have XcodeCoverage in sibling folder
  2. How to run tests from Xcode or command line. Maybe this question will resolved after I resolve the first one

Some minors:

  1. What is code formatting you're using, how to make sure that my code also following your code standard
  2. You mentioned using CocoaPods, but I don't see Podfile in repository

This issue is not point of saying that I require you help to resolve these question. But is more about making entrance for contribution easier as possible.

And thank you for the great library!

Assertion failure mocked NSFileManager

Hi,

I've been using OCMockito and OCHamcrest for a while now, and I'm very grateful for the hard work you've put into this library.

I've just installed the newest version of each, so my current OC setup is
OCMockito 1.1.0
OCHamcrest 3.0.1

I have a problem trying to test NSFileManager, when I run the method :

  • (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory

I get the following assertion failure in the logs :

*** Assertion failure in NSArray *TKArrayArgumentsForInvocation(NSInvocation *__strong)(), /Users/joreid/Development/Mockito/OCMockito/Source/OCMockito/NSInvocation+TKAdditions.m:102
Unknown.m:0: error: -[RRAudioDownloadTest testDownloadTrackSucceedsTrackIsCopiedIntoTheFileSystem] : -- Unhandled type: ^c

When I print out the instance that I'm running this method on, it looks like this :

(lldb) po self.defaultFileManager
mock object of NSFileManager

I wonder if it's because this method is taking a BOOL * as an argument?

Expected Behaviour:

  • The mocked instance of NSFileManager should not fail on assertion.

given only works for ObjC methods

Default implementation doesn't work in Cedar due to using self in given macro definition. Cedar uses plain C functions, so self isn't available. To compensate, I use this macro:

#ifdef given
#   undef given
#   define given(methodCall) MKTGivenWithLocation([SpecHelper specHelper], __FILE__, __LINE__, methodCall)
#endif

Would be nice to support plain C style of unit tests as well.

Verify method calls with handle (pointer-to-pointer) arguments

There isn’t currently a way to verify method calls on a mock that accept handles as arguments.

For the method - (NSString *)someMethodWithError:(NSError **)error implemented by someMockObject,

NSError *err;
[verify(someMockObject) someMethodWithError:&err];

issues:

*** -[NSProxy doesNotRecognizeSelector:someMethodWithError:] called!

Key-value coding requires two given() declarations

Say I'm mocking Employee, which has a string property "firstName".
In the code under test, it is accessed both as [anEmployee firstName] and [arrayOfEmployees valueForKeyPath:@"firstName"](or somewhat more realistically, [arrayOfDepartments valueForKeyPath:@"employee.firstName"])

As I understand it, my test code needs to do two calls to mock this one parameter:
Employee *mockEmployee = mock([Employee class]);
[given([mockEmployee firstName) willReturn:@"fake-firstname"];
[given([mockEmployee valueForKey:@"firstName") willReturn:@"fake-firstname"];

It'd be nice if the mock object could check calls to valueForKey and try returning answers for the appropriate property if available, thus avoiding the need to sometimes write two versions of effectively the same declarative statement. (Which I've managed to forget a couple of times and confuse myself.)

Can't verify custom objects?

Trying out OCMockito, but am not able to verify whether a message was sent with my object as argument. Here's simplified version of my test:

id comment = mock([CommentInfo class]);
[comment setAbstract:[ComponentInfo componentWithSourceString:@"line"]];
[verify(comment) setAbstract:[ComponentInfo componentWithSourceString:@"line"]];

I want to verify whether the unit test sends setAbstract: message to my comment object and passing it a ComponentInfo object with its sourceString set to "@line". But I get the following error: Expected 1 matching invocation, but received 0. If I change above to use NSString instead of ComponentInfo class, it works...

Not sure if this is something that doesn't work as expected, or my misunderstanding of the framework...

Linker error when using mockClass in an OSX project

When I add the following code to an OSX project:

Class mockStringClass = mockClass([NSString class]);

I get the following linker errors:

Undefined symbols for architecture x86_64:
  "_MKTVerifyWithLocation", referenced from:
      <snip> in <snip>
  "_OBJC_CLASS_$_MKTClassObjectMock", referenced from:
      objc-class-ref in <snip>
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The same code in an iOS project does not produce the linker error, and works as expected.

Evaluate parameters for a Mocked Protocol

Good day,
It looks like there is an issue when trying to evaluate a parameter in a mocked protocol.

Considering the example that comes with the code:

    - (void)testVerifyWithMatcherForPrimitive
    {
        NSMutableArray *mockArray = mock([NSMutableArray class]);

        [mockArray removeObjectAtIndex:2];

        [[verify(mockArray) withMatcher:greaterThan([NSNumber numberWithInt:1]) forArgument:0]
         removeObjectAtIndex:0];    // The 0 is a placeholder, replaced by the matcher
    }

It works like expected, but when I try to replicate this with a mock protocol it always pass the tests, for example:

    - (void)testFirstParameter
    {
        // given
        id<TestProtocol> mockElement = mockProtocol(@protocol(TestProtocol));

        // when
        id toProcess = nil;
        [mockElement process: toProcess];

        // then
        id firstArgumentMatcher = instanceOf([NSArray class]);
        [[verify(mockElement) withMatcher: firstArgumentMatcher forArgument: 0] process: toProcess];
    }

In this test I'm trying to test that the argument is instance of an NSArray class, it shouldn't pass.

OCMockito 1.1.0 and UIImage

Hi Jon,

It seems that version 1.1.0 of OCMockito doesn't like to mock method calls (using given() clauses) that take UIImage parameters?

I see errors such as "Unhandled type: ^@". If I downgrade OCMockito to version 1.0.0, everything works just fine...

What could be the issue here?

Thanks

Resetting the invocations count in a mock during a test

Sometimes I want to verify that something happened at least once, and after testing it I would like to reset that count and test that it didn't happen again.

Adding someKind of reset or clear method for mocks might be really useful for that.
Or is there a way and I missed it?

Capturing arguments?

Is there a mechanism to capture arguments?

Most asynchronous APIs (especially for networking libraries) accept completion blocks. It'd be awesome to be able to capture the completion block and test against it.

For example, suppose I mock a NSURLConnector. (Thanks for showing me we can mock class methods earlier today on StackOverflow!) Then I want to verify that my code calls sendAsynchronousRequest:queue:completionHandler. I'd love to capture the completionBlock and verify the operations in the completion handler.

myblock = //... something I can test against
[verify(connector) sendAsynchronousRequest:urlRequest queue:queue completionHandler:capture(myblock)];

This request is similar to this request for Kiwi.

Make OCHamcrest dependency a submodule

Instead of leaving the non-cocoapods user to write build scripts to copy another repo's product into this one, can you instead point the OCMockito build into OCHamcrest as a submodule to make this more friendly?

alloc class method can not be mocked

If I have a class Foo, and create a class mock for it, I should be able to mock the return value of [Foo alloc].

As per the following test case, this does not appear to work.

//
//  Created by: Robert Atkins
//

    // Class under test

    // Collaborators

    // Test support
#import <SenTestingKit/SenTestingKit.h>

// Uncomment the next two lines to use OCHamcrest for test assertions:
#define HC_SHORTHAND
#import <OCHamcrestIOS/OCHamcrestIOS.h>

// Uncomment the next two lines to use OCMockito for mock objects:
#define MOCKITO_SHORTHAND
#import <OCMockitoIOS/OCMockitoIOS.h>


# pragma mark - Foo test collaborator

@interface MockAllocFoo : NSObject

- (instancetype)init;

@end

@implementation MockAllocFoo

- (instancetype)init
{
    self = [super init];
    if (self) {
        // ...
    }
    return self;
}

- (NSString *)helloWorld
{
    return @"I am Foo";
}

@end


#pragma mark - class under test

@interface ClassUnderTest : NSObject

- (NSString *)methodUnderTest;

@end

@implementation ClassUnderTest

- (NSString *)methodUnderTest
{
    MockAllocFoo *foo = [[MockAllocFoo alloc] init];
    return [foo helloWorld];
}

@end


#pragma mark - Mock alloc test

@interface MockAllocTest : SenTestCase
@end

@implementation MockAllocTest
{
    Class _mockFooClass;
    MockAllocFoo *_mockFoo;

    ClassUnderTest *_classUnderTest;
}

- (void)setUp
{
    _mockFooClass = mockClass([MockAllocFoo class]);
    _mockFoo = mock([MockAllocFoo class]);

    _classUnderTest = [[ClassUnderTest alloc] init];
}

- (void)testMockAlloc
{
    [given([MockAllocFoo alloc]) willReturn:_mockFoo];
    [given([_mockFoo helloWorld]) willReturn:@"I am the mocked foo!"];

    assertThat([_classUnderTest methodUnderTest], equalTo(@"I am the mocked foo!"));
}

@end

Optional protocol methods should not be expected implicitely

When mocking a protocol the mock will respond to the optional implicitly. For example let's say I want to test that a object does not call delegate method if it's not implemented. I would expect to be able to do this:

_object.delegate = mockProtocol(@protocol(ObjectDelegate));
[_object doSomething];
[verifyCount(_object.delegate, never()) objectDidDoSomething:anything()];

Because the mock responds to the selector this will fail.

I expect optional protocol methods to not be implemented until explicitly expected them to be called using given. I realize given implies that there's a return value and some delegates do not have one but am unsure what the best solution is.

The problem lies in the call to protocol_getMethodDescription here. The third argument means the method will return optional methods.

I'm not familiar enough with the inner workings of OCMockito to make it work, but I think this extra check should only be done when I've explicitly indicated that the protocol mock should respond to that optional selector.

verify macro clashes with AssertMacros.h

When I tried to verify some behaviour using Mockito's verify(...) I got the error:

49:18: Implicit declaration of function '__Verify' is invalid in C99
Bad receiver type 'int'

The reason is that XCode thinks I'm talking about the verify macro defined in /usr/include/AssertMacros.h

This shouldn't really happen, since I've declared my imports like so in my target's *.pch file:

    #import "Specta.h"
    #define EXP_SHORTHAND
    #import "Expecta.h"
    #define HC_SHORTHAND
    #import <OCHamcrest/OCHamcrest.h>
    #define MOCKITO_SHORTHAND
    #import <OCMockito/OCMockito.h>

AppCode understands me well enough and knows I'm talking about OCMockito.

How can I tell XCode to prefer OCMockito's macro over /usr/include/AssertMacros.h?

enable checking the captor state in tests

I'd like to implement a test basically looking like this:

[verify(_sut.someProperty) someCall:[captor capture]];

assertThatBool([captor hasValue]);

Right now, I'm using a custom category for this (which should not be necessary). The category calls -value and returns YES but checks for exceptions which will result in NO.

Would you accept a pull request with such a feature?

`unrecognized selector` instead of "proper" test failure

I am using Kiwi and OCMockito.

Setup:

This is my imports:

#import "Kiwi.h"
#define HC_SHORTHAND
#import "OCHamcrest.h"
#define MOCKITO_SHORTHAND
#import "OCMockito.h"

And this is my test case, made to fail:

describe(@"Segues", ^{
        describe(@"entity list segue", ^{
            describe(@"When Awareness is selected", ^{
                __block TNWEntityTableViewController *mockController;
                beforeEach (^{
                    mockController = mock([TNWEntityTableViewController class]);
                    cut.selectedEntityList = @"Awareness";
                    [cut entityListSegueToController:mockController WithSegue:nil];
                });

                it(@"should call beginLoadEntity on the entity list controller", ^{
                    [verify(mockController) beginLoadEntity:@"Awareness_"];
                });
            });
        });
    });

Getting:

error: ViewController_Segues_EntityListSegue_WhenAwarenessIsSelected_ShouldCallBeginLoadEntityOnTheEntityListController (TNWViewControllerSpec) failed: 'View Controller, Segues, entity list segue, When Awareness is selected, should call beginLoadEntity on the entity list controller' [FAILED], NSInvalidArgumentException "+[TNWViewControllerSpec failWithException:]: unrecognized selector sent to class 0xa088edc" raised

When a verify fails.

It is coming from MKTTestLocation.m here:


// As of 2010-09-09, the iPhone simulator has a bug where you can't catch exceptions when they are
// thrown across NSInvocation boundaries. (See http://openradar.appspot.com/8081169 ) So instead of
// using an NSInvocation to call -failWithException: without linking in SenTestingKit, we simply
// pretend it exists on NSObject.
@interface NSObject (MTExceptionBugHack)
- (void)failWithException:(NSException *)exception;
@end


void MKTFailTest(id testCase, const char *fileName, int lineNumber, NSString *description)
{
    NSString *theFileName = @(fileName);
    NSException *failure = [MKTException failureInFile:theFileName
                                                atLine:lineNumber
                                                reason:description];
    [testCase failWithException:failure];  // <--- throws here.
}

How to stub class methods?

This is more a feature request/question...
Is it possible to stub out class methods?

Examples are like:

NSNotificationCenter *center = mock([NSNotificationCenter class]);
[given([NSNotificationCenter defaultCenter]) willReturn:center];

I keep trying this but I don't see my mock object being returned...

verify() does not work with methods that have NSError** as parameter

For my API operation tests I mock the actual http request. For this I have put all my http code into an own server request class that I can replace in the operation.

It looks like this:

@interface MyServerRequest : NSObject
- (id)sendRequestWithParameters:(NSDictionary *)parameters error:(NSError **)error;
@end

Now I have a unit test that tests the operation if the correct parameters are passed:

MyServerRequest *serverRequest = mock([MyServerRequest class]);

MyOperation *operation = [MyOperation operation] initWithServerRequest:serverRequest]
[operation main]; // in the main the sendRequestWithParameters is called

MKTArgumentCaptor *requestParameterArgument = [[MKTArgumentCaptor alloc] init];
[verify(serverRequest) sendRequestWithParameters:[requestParameterArgument capture] error:nil];

The problem here is that the verify does not work, because the error parameter cannot be ignored will nil or anything()

My solution so far is to remove the MKTPointerArgumentGetter from the MKTArgumentGetterChain, then the error parameter can be ignored, and all my test are working fine.

My opinion is that if NSObject** parameters cannot be captured, than they should be ignored (like this was the case in the previous versions of OCMockito)

Mocking a Class that conforms to a Protocol

Is it possible to create a mock Class that conforms to a protocol?

Here is an example of the code I am trying to test:

Class objectClass = [self getObjectClassFromSomewhere];

if (objectClass && ![objectClass conformsToProtocol:@protocol(SomeObjectProtocol)]) {
    @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Class does not implement SomeObjectProtocol." userInfo:nil];
}

I see that OCMockito has a mockClass and mockObjectAndProtocol methods. What I seem to need here is a mockClassAndProtocol method.

How would I go about implementing this?

Mock CoreData generated class

Hi,

I'm new to ios development and started using OCMockito. I'm currently investigating trying to test some functionality where I mock class with @dynamic properties. So far I have crash about not responding selector. Are there workaround, proper solution for this?

Kind Regards,
Eugen

Mockito has problems mocking arrays

When you try to mock an array like this

[mock([NSMutableArray class]) addObject:@"test"];

The test will fail due to the follwing exception:

error: testMock XY failed: -[__NSArrayM setObject:atIndexedSubscript:]: unrecognized selector sent to instance 0x1b79330

It looks like mockito doesn't like the new array literals.

TKArrayArgumentsForInvocation does not handle NSError**

The stub below worked with 1.0.0, but now ends up at NSCAssert1(NO, @"-- Unhandled type: %s", argType); in NSInvocation+TKAdditions.m. It might be possible to wrap NSError** in an NSValue, and then unwrap everywhere the array on args is used?

#import <XCTest/XCTest.h>
#import <CoreData/CoreData.h>

#define HC_SHORTHAND
#import <OCHamcrest.h>

#define MOCKITO_SHORTHAND
#import <OCMockito/OCMockito.h>

@interface OCMockitoTestTests : XCTestCase

@end

@implementation OCMockitoTestTests

- (void)testShouldBeAbleToMockNSFetchedResultsController
{
    NSFetchedResultsController *frcMock = mock([NSFetchedResultsController class]);
    [given([frcMock performFetch:nil]) willReturnBool:YES];
}

@end

+[NSException mkt_failureInFile:atLine:reason:]: unrecognized selector sent to class

I am attempting to add OCMockito and OCHamcrest to my current project. It is currently quite small. I am using Google Analytics mobile in my app and would like to ensure that my code is calling the appropriate methods accordingly. I am attempting to mock a protocol, however when I attempt to verify that a method was called on the protocol my test fails and I receive this error:
+[NSException mkt_failureInFile:atLine:reason:]: unrecognized selector sent to class.

I have tried to duplicate this same error with a brand new project and I cannot. I don't know what problem I could have with my project that would cause this, and I have run out of ideas on what to do to fix this.

Please help

Cocoapods OCMockitoIOS and OCHamcrestIOS headers

Hi,

I'm using this pod:

pod 'OCMockito', '~> 1.0.0'

But Xcode can't find this headers:

#define HC_SHORTHAND
#import <OCHamcrestIOS/OCHamcrestIOS.h>

#define MOCKITO_SHORTHAND
#import <OCMockitoIOS/OCMockitoIOS.h>

So I'm using this instead:

#define HC_SHORTHAND
#import <OCHamcrest/OCHamcrest.h>

#define MOCKITO_SHORTHAND
#import <OCMockito/OCMockito.h>

Is it anything wrong with the pod? Or I will just fine using those headers?

Thanks for the help.

OCMockito 1.3.0 and corrupted memory

This is more of a question rather than an issue, but.

I've recently updated one of our older projects to OCMockito 1.3.0 and I've noticed a rather high amount of BAD_ACCESS crashes. I've initially thought that there's some sort of an overrelease going on somewhere, but unfortunately NSZombies showed nothing.

After a bit of researching I've came to conclusion that this is an issue with corrupted memory - something's writing over other objects. I'm not yet sure what, or where (need bit more time to research), but downgrading to 1.2.0 fixed the issue.

Going through 1.3.0 vs 1.2.0 diff I can't exactly see any new code that could lead to such crashes (actually it seems that it was a minor refactor + iOS deployment target bump).

The only other major difference is OCHamcrest, which got a major bump from 3.0.1 to 4.0.1. We're using OCHamcrest a lot and this might actually be an issue.

So, ultimately, my question is: did anyone notice similar issues?

OCMockito for Swift

I know this might be a somewhat difficult task, cause Swift does not provide something like defines (although one could use global functions instead) and pure Swift objects (not inheriting from NSObject) have a completely different, less dynamic and probably harder to mock internal structure.

Also so see http://ocmock.org/swift/ .

All ideas welcome!

Any next call to any other mock after verify(...) is verified

Consider following code:

[verifyCount(foo, never()) doSomethingWithBaz:[bar baz]];

where (1) bar is a mocked object OR (2) any mocked object is messaged during the invocation of -baz.

Expected:
Number of -doSomethingWithBaz calls to foo is verified.

Actual:
Number of calls of -baz to bar is verified (if it is a mock) or any other calls to a mock object that is invoked during the invocation of -baz.

verify(...)-family macros seem to set up verification in shared core and when _any_ mocked object is called, the verification is done for it. This can lead to less-than-obvious errors in end-user test specs.

mockClass crashes on 64-bit (Mac or iOS)

Was trying out OCMockito to compare it to OCMock but ran into the following issue trying out mocking a class object from the README example. It works well under 1.0.0 but crashes under 1.1.0 and 1.2.0.

    Class stringClassMock = mockClass([NSString class]);
    [given([stringClassMock string]) willReturn:@"A string"];
    assertThat([stringClassMock string], equalTo(@"A string"));
* thread #1: tid = 0x985577, 0x000000010086af12 libobjc.A.dylib`cache_getImp + 18, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x88)
    frame #0: 0x000000010086af12 libobjc.A.dylib`cache_getImp + 18
    frame #1: 0x000000010085f4bc libobjc.A.dylib`lookUpImpOrForward + 50
    frame #2: 0x000000010085f457 libobjc.A.dylib`lookUpImpOrNil + 20
    frame #3: 0x000000010085672f libobjc.A.dylib`class_respondsToSelector_inst + 35
    frame #4: 0x000000010085670a libobjc.A.dylib`class_respondsToSelector + 11
    frame #5: 0x0000000100be0b6e CoreFoundation`___forwarding___ + 430
    frame #6: 0x0000000100be0938 CoreFoundation`_CF_forwarding_prep_0 + 120
    frame #7: 0x0000000102db8e60 TestingPlaygroundTests`-[TestingPlaygroundTests testOCMockito](self=0x000000010cfd6e50, _cmd=0x0000000102c0fa10) + 672 at TestingPlaygroundTests.m:45
    frame #8: 0x0000000100be4f1c CoreFoundation`__invoking___ + 140
    frame #9: 0x0000000100be4dc4 CoreFoundation`-[NSInvocation invoke] + 308
    frame #10: 0x0000000102e34c40 XCTest`-[XCTestCase invokeTest] + 161
    frame #11: 0x0000000102e34d2c XCTest`-[XCTestCase performTest:] + 91
    frame #12: 0x0000000102e35a75 XCTest`-[XCTest run] + 65
    frame #13: 0x0000000102e344df XCTest`-[XCTestSuite performTest:] + 125
    frame #14: 0x0000000102e35a75 XCTest`-[XCTest run] + 65
    frame #15: 0x0000000102e344df XCTest`-[XCTestSuite performTest:] + 125
    frame #16: 0x0000000102e35a75 XCTest`-[XCTest run] + 65
    frame #17: 0x0000000102e344df XCTest`-[XCTestSuite performTest:] + 125
    frame #18: 0x0000000102e35a75 XCTest`-[XCTest run] + 65
    frame #19: 0x0000000102e371b4 XCTest`+[XCTestProbe runTests:] + 138
    frame #20: 0x00000001000012e1 xctest`___lldb_unnamed_function9$$xctest + 163
    frame #21: 0x0000000100001521 xctest`___lldb_unnamed_function11$$xctest + 222
    frame #22: 0x0000000100001017 xctest`___lldb_unnamed_function2$$xctest + 35
    frame #23: 0x00000001017da5fd libdyld.dylib`start + 1

False negative with NSString constants

I'm writing test for checking that alertManager was called.

static NSString *const WRONG_DATA_TITLE = @"Wrong Data";
static NSString *const EMPTY_DATA_MESSAGE = @"Email and Password can not be empty";

Class:

if ([self isEmpty:email] || [self isEmpty:password]) {
        [self.alertManager showAlertMessage:WRONG_DATA_TITLE withTitle:EMPTY_DATA_MESSAGE];
}

Test:

- (void)testAlertThatInputIsEmptyWhenPasswordIsNil {
    [controller requestLoginWithEmail:@"[email protected]" andPassword:nil];

    [verify(self.mockedAlertManager) showAlertMessage:EMPTY_DATA_MESSAGE withTitle:WRONG_DATA_TITLE];
}

And I'm getting Expected 1 matching invocation, but received 0.

To be sure I added MKTArgumentCaptor and I see in debug that it has proper value.

What can be the issue?

BlockMatchingTest crashes

On my system BlockMatchingTest testMatchNilValue crashes.

2013-07-06 11:34:59.472 otest[8166:303] -[HCIsNil copyWithZone:]: unrecognized selector sent to instance 0x7f98cd107450

The crash occurs in setInvocationForPotentialStubbing in the line

[invocation retainArguments];

It looks like because the argument is declared as a block, retainArguments tries to copy it (which would usually be the right thing). However the matchers can't be copied.

Would it make sense to implement copy in matchers (by returning self) in OCHamcrest?

Missing Commits.

Its seems like: 317fa0cf75c9b0d73d2be335789c556537be7fd2 no longer exists in this repository. This seems rather strange, whats the motivation for history rewrites?

Separating OCMockito from OCHamcrest

I'm not sure how feasible this is, but it would be nice if OCMockito didn't depend on OCHamcrest and could be used with other matching frameworks without requiring OCHamcrest.

OCMockito and Memory Leaks

Hi,

We are having a bunch of issues in our unit tests lately because of Memory Leaks.
I have tracked it down to the fact that OCMockito's given clauses seem to retain all of the objects that are passed to it.

OCMockito's objects never get deallocated; hence our objects do not get deallocated when we nil them out during tearDown.

This is causing our unit tests to fail because each unit test affects the other.
Are there any fixes to this coming?

I have to modify my application logic because of these failures; or have to sacrifice unit test coverage because of the limitations of this library...any thoughts?

Ronak

Block support?

Hi,

Thanks for a great mocking framework! But I have some problems with blocks.

So my question is: Will you at a given time support blocks?

Thanks!

Mocking class methods - is it possible to pass that mocked class method 'in'?

I know you can mock a class method so:
Class mockStringClass = mockClass([NSString class]);
but I have an instance method that calls something like
NSArray *array = [MyModel queryForLatestData];
I can't see any way with OCMockito to mock out that call. Is this possible?

E.g.
MyClass *obj = [[MyClass alloc] init];
[obj callSomeMethodThatMakesTheAboveClassMethodCall];

My class method is not returning a singleton; in that case, I would inject the singleton,
so then the instance could be mocked..
You can have a class property as a way of passing a class in, but it is too generically
typed and thus unsafe:
@Property (strong) Class myclass;

Are partial mocks coming back?

Hey there,

thanks for this great framework at first, it's really great! I saw that you earlier removed partial mocks (spy) but removed it shortly after. Is there any chance that they are coming back? Would try to implement them myself but I don't really have a clue how to do this and want to avoid the subclassing approach (since I'm heavily testing UIViewControllers).

Thanks in advance!

Podspec defines dependency on OCHamcrest

Tried to create a podfile using

pod 'OCHamcrest',           '~> 2.0.1'
pod 'OCMockito',             '~> 0.23'

which produces an error during pod update

[!] OCMockito (0.23) tries to activate OCHamcrest (= 1.9)', but already activated version2.0.1' by Podfile.

What shall I do here?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.