Очевидным решением было бы вместо этого использовать внедрение зависимостей.Вы уже знакомы с этим термином, поэтому я предполагаю, что вы достаточно изобретательны, чтобы найти информацию, необходимую для применения инъекций зависимостей к классу под рукой (для этого есть информация по всему Интернету - Википедия, YouTube, этот сайти многое другое ..).
Однако, учитывая сценарий, в котором вы хотите протестировать этот класс и не хотите или не можете изменить его исходный код и исправить нарушение, тогда, если EmailService
и EmailService#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
нашим собственным классом (возможно, однажды я отредактирую)ответ на этот вопрос и пример этого).
Хотя эти методы позволяют тестировать классы-нарушители, они предназначены для тестов, которые трудно понять и поддерживать.Я дважды подумал, прежде чем добавить тест, подобный одному из вышеперечисленных, в свой набор тестов, и рассмотрю возможность рефакторинга или замены тестируемого класса задолго до этого.