アウグストのように、私はこれが一般的に良い考えであるとは確信していません。しかし、私はちょっとした遊びを我慢できませんでした。提供された引数を格納して返すカスタム マッチャーとカスタム アクションを作成しました。
注: これは本番環境で使用できるコードとはほど遠いものです。私はちょうどいくつかの楽しみを持っていました。ソリューションを証明する自己完結型の単体テストを次に示します。
@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);
}
}
}
より良い計画
具体的な例を示したので、上記の JMock ハッカーに頼らずに Java でこれをテストする方法を紹介できます。
まず、あなたが投稿したもののいくつかの 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());
}
}