Question

I have a strong preference for a highly predictable Arrange Act Assert format for unit tests.

Because Kiwi doesn't have an explicit verify statement for mocks, it forces a different pattern, something like:

// Arrange
Thing *mockThing = [CollaboratingClass mock];
TestedClass *sut = [[TestedClass alloc] initWithCollaborator:mockThing];

// Expect (collaboration expectations)
[[[mockThing should] receive] someMessage];

// Act
[mockArray someMethodInvolvingCollaborator];

// Assert (state expectations)
[[sut.someProperty should] equal:someValue];

I know that the verification happens anyway, but prefer to be able to quickly scan tests, with assertions and expectations being together in one predictable place. This is nicely enabled by mockito (and its Objective-C implementation OCMockito), where the verification step specifies the method call post-hoc, making a prior expectation step unnecessary.

I'm a relative Kiwi novice, so I may have missed something in the docs. Is there a way of explicitly verifying Kiwi mocks?

Was it helpful?

Solution

The link you provided about Arrange Act Assert has this to say about the benefits of the pattern (emphasis added):

Benefits:

  • ...
  • Makes some TestSmells more obvious:
    • Assertions intermixed with "Act" code.
    • Test methods that try to test too many different things at once

Especially if your goal is to be able to quickly scan assertions, I think your example would be better broken up into two test cases: a collaboration test, and a separate test for how the object's state changes.

I actually think there's a fourth step here, specific to collaboration tests, which is Expect. Kiwi lets you Arrange, Expect, Act, where OCMock actually requires you to add a fourth, redundant Assert step by requiring [mockThing verify].

I think this would be a better way to set up those tests:

__block TestedClass *sut;
beforeAll(^{
    sut = [[TestedClass alloc] initWithCollaborator:mockThing];
}

// Collaboration: Arrange, Expect, Act
it(@"sends someMessage to mockThing", ^{
    // Arrange
    Thing *mockThing = [CollaboratingClass mock];

    // Expect
    [[[mockThing should] receive] someMessage];

    // Act
    [mockArray someMethodInvolvingCollaborator];
}

// State: Arrange, Act, Assert
it(@"sets someProperty to the return value of someMethod", ^{
    // Arrange
    NSString *expectedString = @"foo";
    Thing *mockThing = [CollaboratingClass mock];
    [[mockThing stubAndReturn:expectedString] someMessage];

    // Act
    [mockArray someMethodInvolvingCollaborator];

    // Assert
    [[sut.someProperty should] equal:expectedString];
}

And the benefit you get with this setup is that if you ever need branch based on the return value from the collaborator, you can just add another test which stubs someMethod to return a different result, and make a different assertion:

it(@"sets someProperty to nil if someMethod returns baz", ^{
    // Arrange
    Thing *mockThing = [CollaboratingClass mock];
    [[mockThing stubAndReturn:@"baz"] someMessage];

    // Act
    [mockArray someMethodInvolvingCollaborator];

    // Assert
    [sut.someProperty shouldBeNil];
}

Ultimately I think Kiwi is doing us a favour by not requiring us to verify our test doubles.

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