Тестируемый модуль: Impl или интерфейс? ⇐ JAVA
-
Anonymous
Тестируемый модуль: Impl или интерфейс?
Предположим, у меня есть интерфейс и класс реализации, который его реализует, и я хочу написать для этого модульный тест. Что мне следует протестировать: интерфейс или Impl?
Вот пример:
публичный интерфейс HelloInterface { общественная недействительность SayHello(); } публичный класс HelloInterfaceImpl реализует HelloInterface { частная цель PrintStream = System.out; @Override общественный недействительный SayHello () { target.print("Привет, мир"); } общественная недействительность setTarget (цель PrintStream) { this.target = цель; } } Итак, у меня есть HelloInterface и HelloInterfaceImpl, которые его реализуют. Что такое интерфейс тестируемого модуля или Impl?
Я думаю, это должен быть HelloInterface. Рассмотрим следующий эскиз теста JUnit:
публичный класс HelloInterfaceTest { частный HelloInterface привет; @До общественный недействительный setUp () { привет = новый HelloInterfaceImpl (); } @Тест общественный недействительный testDefaultBehaviourEndsNormally () { привет.sayHello(); // здесь нет NullPointerException } @Тест public void testCheckHelloWorld() выдает исключение { ByteArrayOutputStream out = новый ByteArrayOutputStream (); Цель PrintStream = новый PrintStream (выход); PrivilegedAccessor.setValue(привет, «цель», цель); //Вы можете использовать ReflectionTestUtils вместо PrivilegedAccessor //действительно это ДИ //((HelloInterfaceImpl)hi).setTarget(target); привет.sayHello(); Строковый результат = out.toString(); AssertEquals("Привет, мир", результат); } } На самом деле я закомментировал основную строку.
((HelloInterfaceImpl)hi).setTarget(target);
Метод setTarget() не является частью моего публичного интерфейса, поэтому я не хочу случайно вызывать его. Если я действительно хочу позвонить, мне следует потратить немного времени и подумать об этом. Например, это помогает мне понять, что на самом деле я пытаюсь сделать внедрение зависимостей. Это открывает для меня целый мир новых возможностей. Я могу использовать какой-либо существующий механизм внедрения зависимостей (например, Spring), я могу смоделировать его самостоятельно, как я это делал на самом деле в своем коде, или применить совершенно другой подход. Присмотритесь, подготовка PrintSream была не такой простой, может быть, вместо этого мне стоит использовать макет объекта?
РЕДАКТИРОВАТЬ: Я думаю, мне следует всегда сосредоточиться на интерфейсе. С моей точки зрения, setTarget() не является частью «контракта» класса impl, он служит уловкой для внедрения зависимостей. Я думаю, что любой общедоступный метод класса Impl следует рассматривать как частный с точки зрения тестирования. Однако это не значит, что я игнорирую детали реализации.
См. также «Должны ли частные/защищенные методы проходить модульное тестирование?»
EDIT-2 В случае нескольких реализаций\нескольких интерфейсов я бы протестировал все реализации, но когда я объявляю переменную в своем методе setUp() Я бы определенно использовал интерфейс.
Предположим, у меня есть интерфейс и класс реализации, который его реализует, и я хочу написать для этого модульный тест. Что мне следует протестировать: интерфейс или Impl?
Вот пример:
публичный интерфейс HelloInterface { общественная недействительность SayHello(); } публичный класс HelloInterfaceImpl реализует HelloInterface { частная цель PrintStream = System.out; @Override общественный недействительный SayHello () { target.print("Привет, мир"); } общественная недействительность setTarget (цель PrintStream) { this.target = цель; } } Итак, у меня есть HelloInterface и HelloInterfaceImpl, которые его реализуют. Что такое интерфейс тестируемого модуля или Impl?
Я думаю, это должен быть HelloInterface. Рассмотрим следующий эскиз теста JUnit:
публичный класс HelloInterfaceTest { частный HelloInterface привет; @До общественный недействительный setUp () { привет = новый HelloInterfaceImpl (); } @Тест общественный недействительный testDefaultBehaviourEndsNormally () { привет.sayHello(); // здесь нет NullPointerException } @Тест public void testCheckHelloWorld() выдает исключение { ByteArrayOutputStream out = новый ByteArrayOutputStream (); Цель PrintStream = новый PrintStream (выход); PrivilegedAccessor.setValue(привет, «цель», цель); //Вы можете использовать ReflectionTestUtils вместо PrivilegedAccessor //действительно это ДИ //((HelloInterfaceImpl)hi).setTarget(target); привет.sayHello(); Строковый результат = out.toString(); AssertEquals("Привет, мир", результат); } } На самом деле я закомментировал основную строку.
((HelloInterfaceImpl)hi).setTarget(target);
Метод setTarget() не является частью моего публичного интерфейса, поэтому я не хочу случайно вызывать его. Если я действительно хочу позвонить, мне следует потратить немного времени и подумать об этом. Например, это помогает мне понять, что на самом деле я пытаюсь сделать внедрение зависимостей. Это открывает для меня целый мир новых возможностей. Я могу использовать какой-либо существующий механизм внедрения зависимостей (например, Spring), я могу смоделировать его самостоятельно, как я это делал на самом деле в своем коде, или применить совершенно другой подход. Присмотритесь, подготовка PrintSream была не такой простой, может быть, вместо этого мне стоит использовать макет объекта?
РЕДАКТИРОВАТЬ: Я думаю, мне следует всегда сосредоточиться на интерфейсе. С моей точки зрения, setTarget() не является частью «контракта» класса impl, он служит уловкой для внедрения зависимостей. Я думаю, что любой общедоступный метод класса Impl следует рассматривать как частный с точки зрения тестирования. Однако это не значит, что я игнорирую детали реализации.
См. также «Должны ли частные/защищенные методы проходить модульное тестирование?»
EDIT-2 В случае нескольких реализаций\нескольких интерфейсов я бы протестировал все реализации, но когда я объявляю переменную в своем методе setUp() Я бы определенно использовал интерфейс.
Мобильная версия