有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用模拟对象编写单元测试?

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

我有一个类方法eat(),它调用FatDude类eatThemAll()

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类。我可以考虑的一种方法是更改代码,以传递ClassA的FatDude to 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概念,更改源代码是可以的,但我想听听 如果我上面所说的是正确的做法,我会给出一些意见或建议


共 (2) 个答案

  1. # 1 楼答案

    对。由于单元测试,您直接偶然发现了一些好的设计。如果你仔细观察,你会发现你移除了classA和FatDude之间的耦合。现在FatDude可以成为一个界面,在需要时传递行为。ClassA不需要知道它得到了什么样的胖子,也不需要知道如何构造一个胖子(带奶酪汉堡?)

    你的解决方案正是我应该做的。只要您了解进行此类更改的原因和好处/缺点,就可以更改代码以适应TDD

  2. # 2 楼答案

    mock和Dependency Inversion Principle(DIP)齐头并进,在大多数语言中,mock通过接口将类解耦而工作得最好

    在你的例子中,这将在你不需要更改代码的情况下工作:(编辑:我的意思是,在将来,如果你以这种方式设计你的应用程序,你将不需要将代码更改为模拟依赖项:))

    • 抽象接口
    • 具体的类fatude(和mockfatude)应该实现IDude接口
    • 提供一种机制,用于“设置”IDude实例或将其注入classA——依赖项注入(构造函数或get/set);或服务定位器模式最有效(替换具体的classfactory)

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