2015-02-24 5 views
11

Я использую Java 8 в течение нескольких месяцев, и я начал использовать выражения Lambda, которые очень удобны для некоторых случаев. Тем не менее, я часто сталкиваюсь с некоторыми проблемами для модульного тестирования кода, использующего Lambda.Код единицы измерения с Java 8 Lambdas

Возьмем в качестве примера следующий псевдокод:

private Bar bar; 

public void method(int foo){ 
    bar.useLambda(baz -> baz.setFoo(foo)); 
} 

Один подход был бы просто проверить вызов на панели

verify(bar).useLambda(Matchers.<Consumer<Baz>>.any()); 

Но, делая это, я не испытываю Код Лямбды.

Также обратите внимание, что я не в состоянии заменить лямбда со ссылкой метод и использование метода:

bar.useLambda(This::setFooOnBaz); 

Потому что я не буду иметь Foo на этом методе. Или, по крайней мере, это то, что я думаю.

У вас была эта проблема раньше? Как я могу проверить или реорганизовать свой код, чтобы проверить его правильно?


Редактировать

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

ответ

14

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

Обычная альтернатива заключается в том, чтобы реорганизовать лямбда в именованный метод и использовать ссылку на метод из кода продукта и вызывать метод по имени из тестового кода. Как вы заметили, этот случай не может быть реорганизован таким образом, потому что он захватывает foo, и единственное, что может быть зафиксировано ссылкой метода, это приемник.

Но answer from yshavit касается важного вопроса о том, необходимо ли проводить отдельные тесты частных методов. Лямбда, безусловно, можно считать частным методом.

Здесь есть и большая точка. Одним из примеров модульного тестирования является то, что вам не нужно тестировать все, что есть too simple to break. Это хорошо согласуется с идеальным случаем для лямбда, который является таким простым выражением, что это, очевидно, правильно. (По крайней мере, это то, что я считаю идеальным.) Рассмотрим пример:

baz -> baz.setFoo(foo) 

Есть ли какие-либо сомнения, что это лямбда-выражение, когда вручают Baz ссылку, будет вызывать его метод setFoo и передать его foo в качестве аргумента? Возможно, это так просто, что его не нужно тестировать на единицу.

С другой стороны, это всего лишь пример, и, возможно, фактическая лямбда, которую вы хотите протестировать, значительно сложнее. Я видел код, который использует большие, вложенные, многострочные лямбды. См. this answer и его вопрос и другие ответы, например. Такие лямбды действительно трудно отлаживать и тестировать. Если код в лямбде достаточно сложный, что он требует тестирования, возможно, этот код следует переделать из лямбда, чтобы его можно было протестировать с использованием обычных методов.

+0

Вы были правы, когда сказали, что моя настоящая лямбда немного сложнее, чем набор, но все же достаточно просто считать, что она не сломается. В конце концов, возможно, я просто пытаюсь выполнить тестирование на 100% кода, и это основная проблема. Благодаря! – Fdiazreal

11

Относитесь к лямбдам, как к частному методу; не проверяйте его отдельно, а скорее проверяйте его эффект. В вашем случае при вызове method(foo) должно произойти bar.setFoo - так, позвоните method(foo), а затем подтвердите bar.getFoo().

+1

Согласовано, не проверяйте единицу измерения лямбда; единица тестирует результат. – whitfin

+0

Как вы можете проверить 'baz.setFoo' без штрих-кода, следовательно, используя bar как макет? – Fdiazreal

+3

@Fdiazreal: по мере того, как вы передаете код на 'Bar', нет смысла тестировать это действие без создания бара. Конечно, вы можете также проверить 'baz.setFoo (foo)' самостоятельно. Поскольку 'setFoo' - обычный метод, у вас не должно быть проблем с его тестированием - просто забудьте о лямбда. – Holger