Search code examples
unit-testingocmockavcapturedevice

OCMock and AVCaptureDeviceInput


I'm in the process of updating our test suite from OCMock 2 to OCMock 3 and am running into a few issues. One of the issue is that we're trying to mock AVCaptureDeviceInput.

For one of the test we want to return a mocked instance AVCaptureDeviceInput when a class method is called on AVCaptureDeviceInput.

in our setup method:

 self.mockAVCaptureDeviceInputClass = [OCMockObject mockForClass:[AVCaptureDeviceInput class]];

in our test:

    id deviceInput = [OCMockObject mockForClass: [AVCaptureDeviceInput class]];
    [[[[self.mockAVCaptureDeviceInputClass stub] classMethod] andReturn:deviceInput]
     deviceInputWithDevice:mockDevice error:((NSError __autoreleasing **)[OCMArg setTo:nil])];

The issue seems to be that deviceInput overwrites the self.mockAVCaptureDeviceInputClass so that when the classMethod is stubbed, it does not do anything.

An alternative I tried to work around this was to create a mock for an instance of AVCaptureDeviceInput, but that just hangs:

[OCMockObject partialMockForObject: [AVCaptureDeviceInput new]];

with the following stack trace:

    0x000000010938a219 in _object_set_associative_reference ()
    0x0000000108aed5c3 in OCMSetAssociatedMockForClass at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCMFunctions.m:226
    0x00000001144ecce2 in -[OCClassMockObject prepareClassForClassMethodMocking] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCClassMockObject.m:89
    0x00000001144ec934 in -[OCClassMockObject initWithClass:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCClassMockObject.m:31
    0x00000001144f47f6 in -[OCPartialMockObject initWithObject:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCPartialMockObject.m:33
    0x00000001144f1cdd in +[OCMockObject partialMockForObject:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCMockObject.m:58
    0x00000001144e9abe in -[dfsaTests testExample] at /Users/otusweb/Desktop/dfsa/dfsaTests/dfsaTests.m:33

Solution

  • You are running into a common issue: only one mock object can mock class methods for a given class. This is is documented in the limitations section (http://ocmock.org/reference/#limitations). Currently the last mock created "wins".

    What happens in your case is that you set up the first mock in your setup method (self.mockAVCaptureDeviceInputClass) but then you create a second mock for the same class in your test (deviceInput). At this point only the latter one can stub class methods on AVCaptureDeviceInput.

    This problem is getting so common that I have decided to add a warning to OCMock. I'm thinking about the mock object printing a warning in cases where it has active stubs when it gets deactivated for class method stubbing. FWIW, there is some investigation under way to see whether it's possible to have more than one mock object mock class methods on the same class (https://github.com/erikdoe/ocmock/issues/173), but that's not trivial.