【问题标题】:How to write unit test using mock object?如何使用模拟对象编写单元测试?
【发布时间】:2010-12-09 08:11:05
【问题描述】:

我读的模拟示例越多,我就越困惑......

我有调用 FatDude 类eatThemAll() 的classA 方法eat()

public class classA {

   FatDude dude = new FatDude();

   public String eat() {
        String result = dude.eatThemAll();
   }
}

public class FatDude {
   public String eatThemAll() {
       return "never full";
   }
}

现在我想通过模拟 FatDude 类来测试 classA eat() 方法。

public class MockFatDude extends FatDude {
   //override
   public String eatThemAll() {
      return "very full";
   }
}
-------------  test --------------
public class DoTest {

    public void runTest() {
         classA cl = new ClassA();
         String out = cl.eat();
         assertEqual(out, "very full");
    }
}

这个 DoTest runTest() 当然不会使用 MockFatDude 类。我能想到的一种方法是更改​​代码以将 FatDude 传递给 ClassA 的 eat() 方法,例如:

public class classA {

       public String eat(FatDude dude) {
            String result = dude.eatThemAll();
       }
   }

然后把我的测试方法改成:

public class DoTest {

        public void runTest() {
             classA cl = new ClassA();
             String out = cl.eat(new MockFatDude());
             assertEqual(out, "very full");
        }
    }

但正如您所见,我不得不更改源代码以满足我的需要。 这是正确的做法吗?如果我不允许更改我的源代码怎么办? 我知道如果我应用 TDD 概念,可以更改源代码,但我想听听 如果我上面显示的方法是正确的,请提出一些意见或建议。

【问题讨论】:

  • 是java还是C#?你用什么工具?请添加适当的标签。谢谢。
  • @maksymko:我不认为语言或工具对这个问题很重要,除了它是一种面向对象的语言。
  • @calavera:我的意思是为了澄清更正确的分类/过滤等,而不是帮助回答问题。
  • @maksymko:我没有使用 jmock 或 easymock 之类的任何工具,因为我想了解什么是 mock 以及如何使用。大部分教程都展示了使用难以理解的模拟工具的示例。

标签: java unit-testing mocking


【解决方案1】:

Mocking 和 Dependency Inversion Principle (DIP) 齐头并进,在大多数语言中,Mocks 通过接口解耦类来发挥最佳作用。

在您的实例中,这无需更改代码即可工作:(编辑:我的意思是,将来,如果您以这种方式设计应用程序,则无需更改代码来模拟依赖项:))

  • 抽象一个接口 IDude
  • 具体类 FatDude(和 MockFatDude)应实现 IDude 接口
  • 为 IDude 实例提供“设置”或注入到 classA 的机制 - 依赖注入(构造函数或 get/sets);或服务定位器模式效果最好(替换具体的类工厂)

另请注意,许多模拟框架实际上允许您“即时”构建 Mock 具体类(参见 MoQ 等),因此您可以直接在单元测试中创建 MockFatDude 的功能。

【讨论】:

  • @noonb:我认为他在他的示例解决方案中暗示了抽象,否则他将需要覆盖。
  • 由于上面的代码看起来像 Java 而不是 C#,所以我要添加一个指向 stackoverflow.com/questions/22697/…的链接
  • 在非 DI 环境中,您还可以轻松地在纯 java 中构建模拟对象,方法是在被测试的类上使用类似于 getter 注入的方法,并插入充当模拟的匿名内部类。
【解决方案2】:

是的。由于您的单元测试,您直接偶然发现了一些好的设计。如果你仔细观察,你会发现你移除了 classA 和 FatDude 之间的耦合。现在,FatDude 可以成为在需要时传入的行为接口。 ClassA 不需要知道它得到了什么样的 FatDude,或者如何构建 FatDude(有芝士汉堡?)。

您的解决方案正是我会做的。只要您了解进行此类更改的原因和利弊,更改代码以适应 TDD 并没有错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 2013-01-28
    • 2019-08-22
    • 1970-01-01
    相关资源
    最近更新 更多