我读的模拟示例越多,我就越感到困惑......
我有classA方法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类。我可以想到的一种方法是更改代码以将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概念,改变源代码是可以的,但我想听听 一些意见或建议,如果我上面所示的是正确的方法。
答案 0 :(得分:4)
Mocking和Dependency Inversion Principle(DIP)齐头并进,在大多数语言中,Mocks通过接口解耦类,效果最佳。
在您的实例中,这将无需您更改代码即可运行:(编辑:我的意思是,将来,如果您以这种方式设计应用程序,则无需更改代码以模拟依赖项:))
另请注意,许多模拟框架实际上允许您“动态”构建Mock具体类(参见MoQ等人),因此您可以直接在单元测试中创建MockFatDude的功能。
答案 1 :(得分:2)
是。由于你的单元测试,你直接偶然发现了一些好的设计。如果你仔细观察,你会发现你删除了classA和FatDude之间的耦合。现在,FatDude可以成为在需要时传递的行为的接口。 ClassA不需要知道它正在使用什么样的FatDude,或者如何构建FatDude(使用芝士汉堡?)。
您的解决方案正是我所做的。更改代码以适应TDD没有任何问题,只要您了解进行此类更改的原因和缺点/缺点。