Тест лямбда-выражений, вызываемых зависимостями - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь проверить некоторый код внутри лямбда-выражения, который является обратным вызовом из другого класса.

class EmailSender {
    private EmailBuilder emailBuilder;

    public void send() {
        String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
        //send testEmail
    }

    private Consumer<Email> bodyContentAppender() {
        //how to test this through JUnit?
        return email -> email.appendBody("Body Content");
    }
}

interface EmailBuilder {

    String buildEmail(String templateName, Consumer<Email> contentAppender);
}

Лямбда-выражение в методе getBodyContent вызывается из EmailBuilder, который является ложной зависимостью в тесте JUnit для EmailSender. Поскольку я издеваюсь над поведением EmailBuilder, код внутри getBodyContent не вызывается из тестов. Как проверить такой кусок?

EDIT: Захват лямбда-выражения через аргумент Captors не является решением в этом случае, поскольку поведение EmailBuilder является ложным, а фактические методы не вызываются. Во-вторых, email.appendBody выполняет некоторые преобразования в объекте, который передается внешним API, а не просто создать.

Ответы [ 4 ]

0 голосов
/ 23 января 2019

То, что вы пытаетесь сделать здесь, это, по сути, убедиться, что фабричный метод действительно вернул правильный объект. Существует этот связанный вопрос , в котором принято решение не проверять результат фабричного метода, кроме проверки того, что он действительно возвращает объект правильного типа. Поведение этого объекта должно быть проверено в UnitTests для этого типа.

В ответе на этот связанный вопрос о модульном тестировании лямбд Стюарт Маркс утверждает, что

Если код в лямбде достаточно сложен, чтобы его можно было проверить, возможно, этот код следует реорганизовать из лямбды, чтобы его можно было протестировать с использованием обычных методик.

Теперь, реальный вопрос: если бы это была не лямбда, а конкретный класс MyBodyContentAppender, который реализует функциональный интерфейс Consumer<Email>, как бы вы протестировали это? Какие тесты вы бы написали для этого класса?

Возможно, вы бы написали тесты, чтобы убедиться, что при Email вызов accept() действительно вызывает appendBody() с соответствующими параметрами, возможно, при вызове с аргументом null выдается NullPointerException и т. Д. Возможно, вы не убедитесь, что email.appendBody() работает должным образом, поскольку это охватывается тестами для Email. Возможно, вам придется смоделировать Email для этих тестов, если их трудно создать.

Ну, все эти тесты также можно выполнить для лямбды. Ваша проблема в том, что фабрика и тип созданного объекта являются частными, поэтому с точки зрения вашего теста, единственный способ получить доступ к этому объекту - через параметр, передаваемый (mocked) emailBuilder.buildEmail().

Если вы используете Mockito для насмешки emailBuilder, вы можете захватить аргументы этого метода с помощью ArgumentCaptor s (см. 15. Захват аргументов для дальнейших утверждений (начиная с 1.8.0) ), Я уверен, что другие насмешливые библиотеки предоставляют аналогичную функциональность.

0 голосов
/ 22 января 2019

Будет проще проверить, действительно ли вы предоставляете содержимое тела в качестве аргумента, и убедитесь, что метод общедоступен.Если вы намереваетесь сохранить метод как приватный, вам следует проверить открытый метод, вызывающий его.

public Consumer<Email> getBodyContent(String body) {
    //how to test this through JUnit?
    return email -> email.appendBody(body);
}

Затем вы можете проверить его как

@Test
public void testGetBodyContent(){
    .... //send different arguments and assert
    ....
}
0 голосов
/ 23 января 2019

Поэтому, если вы хотите выполнить модульное тестирование своего кода, вы должны убедиться, что он выполняет одну работу за раз. Ваш метод назван getBodyContent, но похоже, что он должен выполнять не больше, чем добавление в тело письма. Следовательно, вы можете использовать этот метод как общедоступный.

Теперь вы можете передать тело и получить содержимое.

@Test
public void testGetBodyContent(){

consumer<Email> consumer = EmailSender.getBodyContent();

assertEquals("Email Content", consumer.accept(<mocked Email object>).getBody())
}
0 голосов
/ 22 января 2019

Большинство фальшивых фреймворков позволяют проверять аргументы, которые используются при вызове методов для макетируемого объекта.Соответственно, вы можете захватить их.

Итак:

  • получают переданный параметр
  • , просто вызывают «код», который он представляет, и проверяют, производит ли он ожидаемые обновления для Emailпредоставленный вами объект.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...