본문 바로가기

카테고리 없음

A tip for Stub implementation on unit tests

When you execute any tests, you need to make some `test doubles`.

This is a tip as to implement `Stub`.

 

Typically, a stub is an object that returns a fixed output. So, It can be implemented like the following.

final class StubDependencyGenerator: DependencyGenerating {
    func generate(option1: Bool, option2: Bool, option3: Bool) -> Dependency {
        Dependency(name: "Stub\(option1)\(option2)\(option3)")
    }
}

 

The Stub object in above is always returns fixed output.

Moreover, you can add the `name` property into the stub to make a better.

final class StubDependencyGenerator: DependencyGenerating {
    var name: String = ""
    func generate(option1: Bool, option2: Bool, option3: Bool) -> Dependency {
        Dependency(name: "\(name)\(option1)\(option2)\(option3)")
    }
}

 

However, the way using parameters is still even inflexible a little. It means, the way of generating a `Dependency` is always fixed regardless of variable; The options as parameters are always appended to name, no matter what the value of the variable is.

 

If you want to flexible control the `generate` method, you can use a closure for generating a `Dependency`.

final class BetterStubDependencyGenerator: DependencyGenerating {
    var generateStub: ((Bool, Bool, Bool) -> Dependency)?
    func generate(option1: Bool, option2: Bool, option3: Bool) -> Dependency {
        return generateStub?(option1, option2, option3) ?? Dependency(name: "")
    }
}

 

I first saw the code similary on the test case in `tuist`.

 

If you add the closure like above `generateStub`, you can control the way to generate a `Dependency` as you want.

func test_generate() {
    // Given
    aDependencyGenerator.generateStub = { option1, _, _ -> Dependency in
        if option1 {
            return Dependency(name: "Option1Stub1") // It used
        } else {
            return Dependency(name: "Stub1")
        }
    }
    bDependencyGenerator.generateStub = { _, _, _ -> Dependency in
        return Dependency(name: "JustStub2")
    }
    
    // When
    let product = subject.generate()
    
    // Then
    XCTAssertEqual(product.name, "Option1Stub1.JustStub2.")
}

 

It makes more isolated and flexible testing. 👍