gpt4 book ai didi

swift - 在测试中使用枚举时避免耦合

转载 作者:搜寻专家 更新时间:2023-11-01 06:32:34 24 4
gpt4 key购买 nike

假设我们有这个枚举

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 现在我所有的测试套件都会失败,因为没有 案例 doThing.

最完美的做法是在测试代码中声明一个虚拟的case 以允许类似

sut.run(action: .dummyAction) {
}

但是 enum 不允许这样做,因为它不允许继承,也不允许扩展来添加 case

我想到的第一个选择是将 Action 转换为协议(protocol),但这种更改在生产中是不必要的,它的唯一目的是在测试代码中完成一些事情。

那么,是否还有其他选择可以实现这一目标?

最佳答案

在使用枚举时如何避免耦合是一个棘手的问题。我自己碰到过几次,但没有可靠的答案:/

您提出的一点是使用协议(protocol),这在生产中感觉没有必要。我有点同意这一点,但大多数时候这是必要的邪恶。

在您展示的示例中,尽管我认为设计中的调整可能会解决部分问题。

特别是在查看这段代码时

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 指定了某种行为。也就是说,当您测试传递 .doThingrun 方法时,您期望的行为与传递 .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枚举,它的唯一目的是描述应该执行哪些不同的操作。

此示例代码在其功能上相当受限,仅运行 () -> () 操作,但您可以在其之上构建以实现更高级的行为。

关于swift - 在测试中使用枚举时避免耦合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45210216/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com