Java依赖注入单元测试

时间:2019-09-18 22:39:30

标签: java testing junit dependency-injection

有人可以对此课程进行junit测试吗?

public class MyApplication {
    private EmailService email = new EmailService();

    public boolean processMessages (String msg , String recipient ) {
        if (msg.length ==0 | | recipient.length ==0 ) {
            return false ;
        }
        return this.email.sendEmail (msg , recipient ) ;
    }
}

3 个答案:

答案 0 :(得分:1)

您的标题使问题很清楚:您没有注入对EmailService的依赖性。为此,添加一个setter或(更好)使其为final并将其添加到构造函数中。

这看起来像:

public class MyApplication {
    private final EmailService email;

    public MyApplication(EmailService email) {
        this.email = email;
    }

    public boolean processMessages (String msg , String recipient ) {
        if (msg.length == 0 || recipient.length == 0 ) {
            return false ;
        }
        return this.email.sendEmail (msg , recipient ) ;
    }
}

一个适当的测试可能是(使用junit和mockito):

private MyApplication app;
private EmailService email;

@BeforeEach
void setup() {
    email = mock(EmailService.class);
    when(email.sendEmail(any(), any())).thenReturn(true);
    app = new MyApplication(email);
}

@Test
void testProcessZeroLengthMessageOrPerson() {
    assertFalse(app.processMessages("", "Person"));
    assertFalse(app.processMessages("Message", "")):
    assertFalse(app.processMessages("", "")):
}

@Test
void testProcessMessage() {
    assertTrue(app.processMessage("Message", "Person"));
    verify(email).sendEmail("Message", "Person");
}

答案 1 :(得分:0)

我使用绿色邮件对邮件服务进行了测试

@Autowired
@Qualifier("emailSenderService")
private SenderService service;

@Autowired
@Rule
public SmtpServerRule smtpServerRule;

@Test
public void send() throws IOException, MessagingException {

    final String CONTENT = Util.randomValue();

    Message message = create();

   /* ... */

    service.send(message);

    Assert.assertTrue(smtpServerRule.getMessages().stream().findFirst().isPresent());

    String messageContent = String.valueOf(smtpServerRule.getMessages().stream().findFirst().get().getContent()).trim();

    Assert.assertTrue(messageContent.equalsIgnoreCase(CONTENT));
}

github

答案 2 :(得分:0)

显而易见的解决方案是改为使用依赖项注入。您已经熟悉了该术语,因此我假设您足够聪明,可以找到所需的信息,以便将依赖项注入应用于当前的类(整个Internet上都有相关信息-Wikipedia,YouTube,此站点还有更多..)。

但是,鉴于您希望测试此类,并且不愿意或无法更改其源代码并更正违规的情况,那么如果EmailServiceEmailService#sendEmail不是最终版本,您可以使用反射:

@Test
public void testWithoutDependencyInjection() throws NoSuchFieldException, IllegalAccessException {
    Map<String, String> expected = new HashMap<>();
    expected.put("Dimitris Sourailidis", "Yes, you can! But you should use dependency injection instead.");
    Map<String, String> actual = new HashMap<>();

    MyApplication app = new MyApplication();
    Field emailField = MyApplication.class.getDeclaredField("email");
    emailField.setAccessible(true);
    emailField.set(app, new EmailService() {
        @Override
        public boolean sendEmail(String msg, String email) {
            actual.put(msg, email);
            return true;
        }
    });

    for (String recipient : expected.keySet()) {
        app.processMessages(recipient, expected.get(recipient));
    }

    assertEquals(expected, actual);
}

如果它们是最终的,那么我们可以创建一个新的ClassLoader,它将用我们自己的类覆盖EmailService(也许有一天我会编辑此答案并提供示例)。

尽管这些技术允许测试有问题的类,但它们却使难以理解和维护的测试成为可能。在将上述测试之一添加到测试套件中之前,我会三思而后行,并会考虑在此之前重构或替换被测类的可能性。