【问题标题】:How do I unit-test a class that depends on another class to change the state of something?如何对依赖于另一个类来更改某物状态的类进行单元测试?
【发布时间】:2010-06-28 22:09:23
【问题描述】:

我有一个类A,它包含一个类B的实例,并且A的函数foo调用B的函数set,它更新了B的状态。这是一个代码示例(在 Javascript 中):

A = function () {
    this.init = function (b) {
        this.b = b
    }

    this.foo = function (val) {
        this.b.set(val)
    }

    this.bar = function () {
        return this.b.get()
    }

}

B = function () {
    this.set = function (val) {
        this.v = val
    }

    this.get = function () {
        return this.v
    }
}

如何对foo 函数进行单元测试,同时保持A 的测试不依赖于B 的实现(使用模拟和存根等等)?

【问题讨论】:

    标签: unit-testing tdd mocking decoupling


    【解决方案1】:

    使用模拟,您可以简单地将A 交给B 的模拟,这将检查set 是否以适当的值被调用。如果你没有模拟框架,在 JavaScript 中你可以简单地创建一个对象:

    b = {  
           setCalled: false,
           expectedValue: <expected>
           set: function(val) {
             <check that val == this.expectedValue>
              this.setCalled = true;
           }
         }
    

    在您设置b 的测试中,使用给定的b 创建一个A,然后调用A.foo 并检查b.setCalled 是否更改为true。您可以类似地向b 添加一个get 方法来检查A.bar。

    在这种情况下,您还应该检查Feature Envy 的气味——当两个类如此紧密耦合时,您应该检查以确保您没有错误地使用某些东西。在您的实际示例中可能没问题,但值得一试。

    【讨论】:

    • “small Feature Envy”应该是“smell”
    • 这不是说测试依赖于实现,对TDD不利吗?如果foo 的实现发生变化,所以它不使用B 的set 怎么办?
    • 请求是用模拟 B 进行测试。我通常不会模拟 B,除非 A 的外部行为是它如何影响 B(例如,如果 B 是外部库)。关于气味的注意事项是(A 的)这种行为可能是有问题的
    【解决方案2】:

    我想出了最好的方法来做到这一点,同时确保 A 的测试不依赖于它的实现,将创建一个模拟 B,它有一个工作的 get 和 set,但写入一个临时变量。

    测试A的代码示例:

    // Mock B
    b = new function () {
        this.set = function (val) {
            this.v = val
        }
    
        this.get = function () {
            return this.v
        }
    }
    
    // Create an instance of A with Mock B
    a = new A().init(b)
    
    // Test A
    
    // ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-22
      相关资源
      最近更新 更多