我的 Java
代码结构如下:
public MyClass {
// some class variables
...
private void process() {
private MyObject obj;
...
obj = createHelper();
...
messageHelper(obj, "One of several possible strings");
...
messageHelper(obj, "Another call with a different string");
...
}
private MyObject createHelper {
MyObject obj = new MyObject();
// some Setter calls
...
return obj;
}
private void messageHelper (MyOject obj, String message) {
...
}
}
我想测试一下,基于属性 obj
(我想指定),messageHelper()
接收正确的字符串。换句话说,我需要控制一种方法的结果并有权访问另一种方法的参数。
我对所有这些 Mock/Stub/Spy 的东西仍然很不安。
在我看来,我需要使用“Spy
”来MyClass
、stub
CreateHelper()
手动”创建的对象,但不确定如何拦截 messageHelper()
的调用参数。
我还注意到Wiki使用 Spies 的注意事项:
Think twice before using this feature. It might be better to change the design of the code under specification.
那么,什么是合适的Spocky方式来完成这项任务呢?
稍微重构的代码: (5/5/14)
public MyClass {
// some class variables
private messageSevice = new messageService();
...
private void process() {
private MyObject obj;
...
obj = new MyObject(parameters ...);
...
if (someCondition) {
messageService.produceMessageOne(obj);
}
...
if (otherCondition) {
messageService.produceMessageTwo(obj);
{
...
}
}
public class MessageService implements IMessageService {
private final static MSG_ONE = "...";
private final static MSG_TWO = "...";
...
public void produceMessageOne(MyObject obj) {
produceMessage(obj, MSG_ONE);
...
}
public void produceMessageOne(MyObject obj) {
produceMessage(obj, MSG_TWO);
}
private void produceMessage(MyObject obj, String message) {
...
}
}
如果有人建议使用 Spock 进行测试的方式,我将不胜感激。
最佳答案
您提到的警告是正确的。可测试的代码和良好的设计之间存在非常好的相关性(我建议观看 Michael Feathers 的讲座以了解原因 http://www.youtube.com/watch?v=4cVZvoFGJTU )。
使用 spy 往往会引起设计问题,因为它通常是由于无法使用常规模拟和 stub 而引起的。
从您的示例中预测有点困难,因为您显然使用了伪名称,但 MyClass
类的设计似乎违反了单一职责原则( http://en.wikipedia.org/wiki/Single_responsibility_principle ),因为它负责处理、创建和消息传递(3 个职责)。
如果您愿意更改设计,以便处理类 (MyClass
) 只进行处理,您将提供另一个进行创建的类 (MyObjectFactory
),还有另一个通过构造函数、setter 方法或依赖项注入(inject)执行消息传递的类 (MyObjectMessager
)。
使用这种新设计,您可以创建正在测试的类的实例 (MyClass
),并向其传递工厂类和消息传递类的模拟对象。然后您就可以在两者上验证您想要的任何内容。
看一下这个示例(使用 Mockito):
public class MyClassTest {
@Test
public void testThatProcessingMessagesCorrectly() {
MyObject object = mock(MyObject.class);
MyObjectFactory factory = mock(MyObjectFactory.class);
when(factory.createMyObject()).thenReturn(object);
MyObjectMessager messager = mock(MyObjectMessager.class);
MyClass processor = new MyClass(factory, messager);
processor.process();
verify(factory).createMyObject();
verify(messager).message(EXPECTED_MESSAGE_1);
verify(messager).message(EXPECTED_MESSAGE_2);
...
verify(messager).message(EXPECTED_MESSAGE_N);
}
...
}
这是一个 Spock 示例(未经测试,使用前请仔细检查...):
public class MyClassSpec extends Specification {
def "check that the right messages are produced with the expected object"() {
given:
def messageService = Mock(IMessageService)
def testedInstance = new MyClass()
testedInstance.setMessageService(messageService)
when:
testedInstance.process()
then:
1 * messageService.produceMessageOne(_)
1 * messageService.produceMessageTwo(_)
}
}
关于java - 如何测试一个方法及其两个助手之间的交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23436130/