gagarwal
gagarwal

Reputation: 4244

Mocking with Swift

Consider the following class named SomeClass written in Swift:

@objc class SomeClass: NSObject
{
    var shouldCallBar = false

    func foo()
    {
        if (shouldCallBar == true)
        {
            bar()
        }
    }

    func bar()
    {
    }
}

For testing the above class foo() method (and similar scenarios mostly written in Objective-C) I was using OCMock like:

- (void) testFooBarShouldBeCalledWhenShouldCallBarIsTrue
{
    SomeClass * someClass = [SomeClass new];

    // Create mocks.
    id mockSomeClass = OCMPartialMock(someClass);

    // Expect.
    [[mockSomeClass expect] bar];

    // Stub.
    someClass.shouldCallBar = YES;

    // Run code under test.
    [someClass foo];

    // Verify.
    [mockSomeClass verify];

    // Stop mocking.
    [mockSomeClass stopMocking];
}

But above test fails with Swift code as OCMock won't works well with Swift.

So I am considering something like entirely in Swift:

class SomeClassTests: XCTestCase
{
    class MockSomeClass: SomeClass
    {
        var isBarCalled = false

        override func bar()
        {
            isBarCalled = true
        }
    }

    func testBarShouldBeCalledWhenTrue()
    {
        let someClass = MockSomeClass()
        someClass.shouldCallBar = true

        someClass.foo()

        XCTAssertTrue(someClass.isBarCalled == true)
    }
}

Note here I am subclassing the original class under test and overriding the bar(). I am not at all touching the foo() implementation.

But the downside is I am using MockSomeClass instance to test foo() of SomeClass. This is something I don't like and not recommended.

Is there any better solution to the problem above?

Notes:

Upvotes: 1

Views: 1041

Answers (1)

Erik Doernenburg
Erik Doernenburg

Reputation: 3014

So, you want to test that one method (foo) does or does not call another method (bar). The foo method is the one under test, and the bar method is, in the wider sense, a dependent component.

If the invocation of bar has lasting side effects, you could get away with testing that the side effect is/isn't present, maybe by querying a property or similar. In that case you don't need mocks or similar.

If there are no side effects then you must substitute the dependency. To do so you need a seam at which you place code that can tell the test whether the method has been invoked or not. For that, I can only see the two options that Jon already discussed in the question you refer to.

You either put the two methods into separate classes, in which case the class boundary is the seam. Using a protocol, or just an informal convention, you can then completely replace the class that implements bar. Dependency injection comes in handy here.

If the two methods must stay in the same class then you have to use a subclass boundary as a seam, i.e. you use the fact that you can override methods and implement a test-specific sublass. It's easiest when you can use a mock framework. If that's not an option you have to write the code yourself, much like what you describe in your question.

Upvotes: 1

Related Questions