说我们有这个枚举
data-parsley-min="1"
此枚举以这种方式使用:
enum Action: String {
case doThing
case doOtherThing
}
现在,我对func run(action: Action, block: () -> Void)
方法进行单元测试,因此我需要以这种方式传递run
:
Action
由于我需要在func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(action: .doThing) {
expect.fulfill()
// Assert something
}
waitForExpectations(timeout: 0.1, handler: nil)
}
上测试其他情况,因此我在整个测试套件中传播了很多ActionRunner
。
问题是:如果我对生产代码进行了更改并将.doThing
更改为case doThing
,那么现在我的所有测试套件都会失败,因为没有case doThatThing
。
完美的做法是在测试代码中声明一个虚拟case doThing
以允许类似
case
但sut.run(action: .dummyAction) {
}
不允许这样做,因为它不允许继承,也不允许扩展添加enum
。
我想到的第一个选项是将case
转换为协议,但这种更改在生产中是不必要的,其唯一目的是在测试代码中完成某些任务。
那么,是否还有其他选择来实现这一目标?
答案 0 :(得分:2)
使用枚举时如何避免耦合的问题是一个棘手的问题。我自己碰到了几次没有坚实的答案:/
您提出的一点是使用协议,在生产中感觉不必要。我有点同意,但大部分时间都是必要的邪恶。
在您展示的示例中,我认为设计中的调整可能会解决部分问题。
特别是在查看此代码时
func run(action: Action, block: () -> Void) {
// ...
}
func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(action: .doThing) {
expect.fulfill()
// Assert something
}
waitForExpectations(timeout: 0.1, handler: nil)
}
我想到的是,您的Action
指定了某种行为。也就是说,当您测试通过run
的{{1}}方法时,您期望的行为与传递.doThing
时的行为不同。
如果这是正确的,是否有任何理由需要将动作枚举实例和一个动作块传递给.doOtherThing
函数?
您可以将定义行为的代码与执行实际操作的代码分开,直到您已经完成的操作。例如:
run
注意:我实际上并没有编译那段代码,所以如果它有一些错误请耐心等待。它应该提出这个想法。
通过这种方式,您protocol Actionable {
var action: () -> () { get }
}
enum Action: Actionable {
case doThing
case doOtherThing
var action {
switch self {
case .doThing: return ...
case .doOtherThing: return ...
}
}
class ActionRunner {
func run(actionable: Actionable) {
actionable.action()
}
}
func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(actionable: FakeActionable()) {
expectation.fulfill()
}
waitForExpectations(timeout: 0.1, handler: nil)
}
class FakeActionable: Actionable {
let action = { }
}
func testDoThing() {
let sut = Action.doThing
sut.action()
// XCTAssert for the expected effect of the action
}
的唯一目的是正确运行给定的ActionRunner
,而Actionable
枚举仅用于描述不同的操作应该执行的操作。
此示例代码相当于它可以执行的操作,只运行Action
个操作,但您可以构建它以实现更高级的行为。
答案 1 :(得分:1)
如果您更改了生产代码,则还必须更改测试代码以测试这些新更改。
也许您可以在Action
类
XCTestCase
变量上设置值
import XCTest
class SharingKitTests: XCTestCase {
var theAction: Action!
override func setUp() {
super.setUp()
self.theAction = .doThing
}
}
然后,您将能够在所有测试方法中使用此 theAction var,如果您需要更改该值,则只需在一个位置更改它。