我最近了解到如何通过创建协议(protocol)并使用默认实现扩展该协议(protocol)来将“Traits/Mixins”添加到 Swift 中的结构/类。这很棒,因为它允许我添加功能来查看 Controller ,而不必向所述 View Controller 添加一堆帮助对象。我的问题是,如何 stub 这些默认实现提供的调用?
这是一个简单的例子:
protocol CodeCop {
func shouldAllowExecution() -> Bool
}
extension CodeCop {
func shouldAllowExecution() -> Bool {
return arc4random_uniform(2) == 0
}
}
struct Worker : CodeCop {
func doSomeStuff() -> String {
if shouldAllowExecution() {
return "Cop allowed it"
} else {
return "Cop said no"
}
}
}
如果我想写两个测试,一个验证当 CodeCop 不允许执行时 doStuff() 返回字符串“Cop allowed it”,另一个测试验证字符串“Cop said no”返回通过 doStuff() 当 CodeCop 不允许执行时。
最佳答案
这很简单,只需在您的测试目标中编写一个附加协议(protocol)即可,该协议(protocol)称为 CodeCopStub
,它继承自 CodeCop
:
protocol CodeCopStub: CodeCop {
// CodeCopStub declares a static value on the implementing type
// that you can use to control what is returned by
// `shouldAllowExecution()`.
//
// Note that this has to be static, because you can't add stored instance
// variables in extensions.
static var allowed: Bool { get }
}
然后扩展 CodeCopStub
的 shouldAllowExecution()
方法,继承自 CodeCop
,根据新的静态变量返回一个值 允许
。这将覆盖任何实现 CodeCopStub
的类型的原始 CodeCop
实现。
extension CodeCopStub {
func shouldAllowExecution() -> Bool {
// We use `Self` here to refer to the implementing type (`Worker` in
// this case).
return Self.allowed
}
}
此时您剩下要做的就是使 Worker
符合 CodeCopStub
:
extension Worker: CodeCopStub {
// It doesn't matter what the initial value of this variable is, because
// you're going to set it in every test, but it has to have one because
// it's static.
static var allowed: Bool = false
}
您的测试将如下所示:
func testAllowed() {
// Create the worker.
let worker = Worker()
// Because `Worker` has been extended to conform to `CodeCopStub`, it will
// have this static property. Set it to true to cause
// `shouldAllowExecution()` to return `true`.
Worker.allowed = true
// Call the method and get the result.
let actualResult = worker.doSomeStuff()
// Make sure the result was correct.
let expectedResult = "Cop allowed it"
XCTAssertEqual(expectedResult, actualResult)
}
func testNotAllowed() {
// Same stuff as last time...
let worker = Worker()
// ...but you tell it not to allow it.
Worker.allowed = false
let actualResult = worker.doSomeStuff()
// This time, the expected result is different.
let expectedResult = "Cop said no"
XCTAssertEqual(expectedResult, actualResult)
}
请记住,所有这些代码都应该放在您的测试目标中,而不是您的主要目标。通过将它放在您的测试目标中,它们都不会影响您的原始代码,并且不需要对原始代码进行修改。
关于swift - 如何在结构/类中 stub Swift "Trait/Mixin"方法进行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48230545/