3

我已经使用 EasyMock 编写了很多 Mock 对象。但是,我经常发现编写部分模拟非常耗时,而且感觉不“正确”。

我会说这是一个设计错误,因为我尝试模拟的类将多个关注点合二为一,因此我应该创建单独的类以分离关注点。

你怎么看?部分嘲笑是好事还是坏事?而且,如果好/坏,为什么?如果你注意到你不能模拟对象,因为你只想模拟几个方法,你会建议什么?

4

3 回答 3

4

如果您发现自己定期创建部分模拟,这可能表明过多的状态和功能被投入到少数类中。这会使您的代码更难维护和推理,因此更难进行单元测试。如果您稍后发现系统中的某些其他组件需要包含在您的一个大型类中的功能子集,它也可能导致代码重复或循环依赖。

尝试识别相关的功能组,并将它们分解为可以独立进行单元测试的较小的辅助类。这将使代码更易于理解,使您能够编写更细粒度的单元测试,并且您可能会在未来某个时候找到重用在不同上下文中拆分的功能的机会。如果您使用的是像 Spring 或 Guice 这样的依赖注入框架,那么当您的应用程序运行时,很容易将这些对象重新连接在一起。

找出重构大型类的最佳方法是从经验中学到的东西。不过,一般来说,我会尝试查看一个类正在做什么,并为它在处理过程中的不同点所扮演的不同角色命名。然后我为这些角色创建新类。例如,如果我有一个类读取服务器日志文件并在找到某些条目时向管理员发送电子邮件,我可能会将其重构为一个知道如何解析日志文件的类,第二个类查找触发器条目,第三个知道如何通知管理员。诀窍是限制每个班级包含多少“知识”。这也使您有机会抽象出一般概念。例如,通过这种方式分解你的课程,

于 2009-11-19T15:07:10.237 回答
0

我个人不喜欢部分模拟,因为这意味着您对ClassAthen 的测试在某种程度上取决于ClassB- 的行为,而模拟的目的是能够ClassA独立于任何合作者的任何实现细节进行测试。

我对“您只想模拟一些方法”的意思感到困惑。您使用的是什么版本的 EasyMock?通常,您只需要为实际调用的方法提供期望值和返回值。或者您的意思是您正在编写这些类的存根版本?

如果您担心您的合作者“将多个关注点合二为一”,您总是可以尝试将其接口分解为几个不同的接口 - 实现类可以实现所有这些。这样,即使您的实现仍然只是一个类,您也可以在单元测试中提供不同的模拟(每个接口一个)。

于 2009-11-19T14:26:06.137 回答
0

我的意见是:部分嘲笑是好的,尤其是当你:

• 调用 JNI 方法的模拟方法,例如

public void methodToTest() {
    int result = invokeLibraryCode();
}

// This method will be mocked
int invokeLibraryCode() {
    // This method is native:
    com.3rdparty.Library.invokeMethod(); 
}

• 使用当前日期操作的模拟方法,而您需要控制日期:

public void methodToTest() {
    Calendar cal = getCurrentDate();
}

// This method will be mocked
Calendar getCurrentDate() {
    return Calendar.getInstance();
}

• mockInputStreamProcess其他抽象类:

public void methodToTest(InputStream is) throws IOException {
    int i = is.read(); // is.read() is mocked
}

当然,您可以使用接口覆盖前两种情况(包装com.3rdparty.Library到您自己的接口、实现CurrentDateProvider等,但我认为这过于复杂了)。

于 2011-09-08T13:59:23.147 回答