"Mock" 固定参数的方法

"Mock" method with fixed parameters

我的项目中有一个 "Mailer" class(当然会发送电子邮件)。为了进行测试,我希望 Mailer#send(String toAddress) 的每个调用都替换为 Mailer#send("mail@example.com").

所以像这样:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassCallingMailer.class})
public class TestClass {

    @Test
    public void testMethod() {
        Mailer mailerMock = mock(Mailer.class);
        // this is where the magic happens; replace any toAddress with fixed email address
        when(mailerMock.send(any(String.class))).thenReturn(mailerMock.send("mail@example.com"));
        try {
            whenNew(Mailer.class).withAnyArguments().thenReturn(mailerMock);
        } catch (Exception e) {
            e.printStackTrace();
        }

        ClassCallingMailer someClass = new ClassCallingMailer();
        assertTrue(someClass.methodSendingMail());
    }
}

这段代码显然是行不通的,但是可以通过某种方式实现吗? 也许这是一个完全错误的方法?

谢谢。


更新

我不太确定这有多好,但它确实有效:

// ClassCallingMailer (no changes, just for completeness)
public class ClassCallingMailer {
    public boolean methodSendingMail() {
        Mailer mail = new Mailer();
        return mail.send(someEmailAddress);
    }
}

// TestMailer (new class)
public class TestMailer extends Mailer {
    // add all constructors from Mailer
    @Override
    public boolean send(String to) {
        return super.send("mail@example.com");
    }
}

// TestClass (with changes)
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassCallingMailer.class})
public class TestClass {

    @Test
    public void testMethod() {
        // changed mock to spy and replaced Mailer with TestMailer
        Mailer mailerMock = spy(TestMailer.class);
        // removed "when(...).thenReturn(...)"
        try {
            whenNew(Mailer.class).withAnyArguments().thenReturn(mailerMock);
        } catch (Exception e) {
            e.printStackTrace();
        }

        ClassCallingMailer someClass = new ClassCallingMailer();
        assertTrue(someClass.methodSendingMail());
    }
}

如果你只想实现这种行为,我建议不要通过模拟来实现。 您可以扩展您的 Mailer class 以拥有一些 TestMailer,您可以在其中执行以下操作:

@Override
public void send(String toAddress){
  super.send("mail@example.com");
}

基本上,您覆盖了 Mailer 的原始发送并使用预定义地址调用它。

您可以在测试中使用这个新子class。