Question

I'm trying to write tests for a tap-to-focus method I've implemented for a AVCaptureVideoPreviewLayer. I want to use a mock AVCaptureDevice in order to pass the various conditions and then to make sure the expected methods are called to handle the actual focusing. Below is the code I'm using.

NSArray *devices = [AVCaptureDevice devices];

for (AVCaptureDevice *device in devices)
{
    if ([device hasMediaType:AVMediaTypeVideo])
    {
        if ([device position] == AVCaptureDevicePositionBack)
        {
            CGPoint point = CGPointMake(focus_y, 1-focus_x);

            if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus] && [device lockForConfiguration:&error])
            {
            ...

This is the test code I have so far:

id deviceMock = [OCMockObject niceMockForClass:[AVCaptureDevice class]];
[[[deviceMock stub] andReturnValue:@YES] hasMediaType:AVMediaTypeVideo];
[(AVCaptureDevice*)[[deviceMock stub] andReturnValue:@(AVCaptureDevicePositionBack)] position];
[[[deviceMock stub] andReturnValue:@YES] isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus];
[[[deviceMock stub] andReturnValue:@YES] lockForConfiguration:nil];

[[deviceMock expect] setFocusPointOfInterest:CGPointZero];
[[deviceMock expect] setFocusMode:AVCaptureFocusModeAutoFocus];
[[deviceMock expect] unlockForConfiguration];
[self waitForCompletion:0.55]; //Wait for UI animation
[deviceMock verify]

I'd like to perform three tests:

  • [AVCaptureDevice devices] returns 0 devices and nothing happens
  • [AVCaptureDevice devices] returns an incompatible device and nothing happens
  • [AVCaptureDevice devices] returns a compatible device and the above test code passes

So I guess my question boils down to is there an easy way to stub and return [AVCaptureDevice devices] class method? Or is it safe to assume that there can only be one AVCaptureDevice on an iPhone/iPad that passes the above conditions so I could store the device as a property and rewrite the method I'm testing so that I can inject the mock AVCaptureDevice?

Was it helpful?

Solution

You can stub the class method "devices" to return an array with the contents of your choosing.

id deviceMock = [OCMockObject niceMockForClass:[AVCaptureDevice class]];

// I think you need to change your return value code to this for the booleans:
[[[deviceMock stub] andReturnValue:OCMOCK_VALUE((BOOL){YES})] hasMediaType:AVMediaTypeVideo];
[[[deviceMock stub] andReturnValue:OCMOCK_VALUE((BOOL){YES})] isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus];
[[[deviceMock stub] andReturnValue:OCMOCK_VALUE((BOOL){YES})] lockForConfiguration:nil];

// No need to wrap the position in an NSNumber
[(AVCaptureDevice*)[[deviceMock stub] andReturnValue:AVCaptureDevicePositionBack] position];

// Stub the class method that returns the devices array
[[[deviceMock stub] andReturn:@[ deviceMock ]] devices];

[[deviceMock expect] setFocusPointOfInterest:CGPointZero];
[[deviceMock expect] setFocusMode:AVCaptureFocusModeAutoFocus];
[[deviceMock expect] unlockForConfiguration];
[self waitForCompletion:0.55]; //Wait for UI animation
[deviceMock verify]

I think that should get you on your way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top