像奥古斯托一样,我不相信这是一个好主意。然而,我忍不住玩了一点。我创建了一个自定义匹配器和一个自定义操作,用于存储和返回提供的参数。
注意:这远非生产就绪代码;我只是玩得很开心。这是一个独立的单元测试,它证明了解决方案:
@RunWith(JMock.class)
public class Example {
private Mockery context = new JUnit4Mockery();
@Test
public void Test() {
final StoringMatcher matcher = new StoringMatcher();
final IDependency mockObject = context.mock(IDependency.class);
context.checking(new Expectations() {
{
// The matcher will accept any Integer and store it
allowing(mockObject).methodToInvoke(with(matcher));
// The action will pop the last object used and return it.
will(new CustomAction("returns previous arg") {
@Override
public Object invoke(Invocation invocation) throws Throwable {
return matcher.getLastValue();
}
});
}
});
Integer test1 = 1;
Integer test2 = 1;
// Confirm the object passed to the mocked method is returned
Assert.assertEquals((Object) test1, mockObject.methodToInvoke(test1));
Assert.assertEquals((Object) test2, mockObject.methodToInvoke(test2));
}
public interface IDependency {
public int methodToInvoke(int arg);
}
private static class StoringMatcher extends BaseMatcher<Integer> {
private final List<Integer> objects = new ArrayList<Integer>();
@Override
public boolean matches(Object item) {
if (item instanceof Integer) {
objects.add((Integer) item);
return true;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("any integer");
}
public Integer getLastValue() {
return objects.remove(0);
}
}
}
更好的计划
现在您已经提供了一个具体的示例,我可以向您展示如何在 Java 中进行测试,而无需求助于我上面的 JMock 黑客。
首先,您发布的一些 Java 版本:
public class Speaker {
private final String firstName;
private final String surname;
private final NameSource nameSource;
public Speaker(String firstName, String surname, NameSource nameSource) {
this.firstName = firstName;
this.surname = surname;
this.nameSource = nameSource;
}
public String introduce() {
String name = nameSource.createName(firstName, surname);
return String.format("Hi, my name is %s", name);
}
}
public interface NameSource {
String createName(String firstName, String surname);
}
public class Formal implements NameSource {
@Override
public String createName(String firstName, String surname) {
return String.format("%s %s", firstName, surname);
}
}
然后是一个测试,它练习了课程的所有有用功能,而不是诉诸于你最初要求的东西。
@RunWith(JMock.class)
public class ExampleTest {
private Mockery context = new JUnit4Mockery();
@Test
public void testFormalName() {
// I would separately test implementations of NameSource
Assert.assertEquals("Joe Bloggs", new Formal().createName("Joe", "Bloggs"));
}
@Test
public void testSpeaker() {
// I would then test only the important features of Speaker, namely
// that it passes the right values to the NameSource and uses the
// response correctly
final NameSource nameSource = context.mock(NameSource.class);
final String firstName = "Foo";
final String lastName = "Bar";
final String response = "Blah";
context.checking(new Expectations() {
{
// We expect one invocation with the correct params
oneOf(nameSource).createName(firstName, lastName);
// We don't care what it returns, we just need to know it
will(returnValue(response));
}
});
Assert.assertEquals(String.format("Hi, my name is %s", response),
new Speaker(firstName, lastName, nameSource).introduce());
}
}