Модульное тестирование
Я не евангелист TDD . Там я это сказал. Я никогда не был в состоянии написать какое-либо программное обеспечение, где для каждого куска кода я сначала написал тест, а затем код. Если вы сделали это и успешно зарабатываете на программировании, пожалуйста, дайте мне знать. Я бы очень хотел узнать вас лучше. Шутки в сторону.
На этом моя разница во взглядах с TDD заканчивается. Помимо написания тестов перед кодом — с которыми я просто не могу заставить свой мозг работать — я большой сторонник модульного тестирования. Я твердо верю в использование JUnit для тестирования всех функциональных возможностей (общедоступные, но не методы получения, методы) Я большой поклонник использования cobertura для сообщения о покрытии кода. Я большой поклонник maven, который позволяет мне собрать все это в один прекрасный HTML-отчет одной командой.
Я буду использовать JUnit 4 для этой серии. Давайте добавим зависимости.
Файл: \ pom.xml
01
02
03
04
05
06
07
08
09
10
11
|
< properties > < junit.version >4.10</ junit.version > </ properties > <!-- Unit testing framework. --> < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >${junit.version}</ version > < scope >test</ scope > </ dependency > |
И давайте добавим тупой класс, чтобы продемонстрировать тестирование.
Файл: /src/main/java/org/academy/HelloWorld.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
package org.academy; public class HelloWorld { private String message = 'Hello world. Default setting.' ; public String greet(){ return message; } public String getMessage() { return message; } public void setMessage(String message) { this .message = message; } } |
И, наконец, JUnit, чтобы проверить это.
Файл: src / test / java / org / academy / HelloWorldTest.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package org.academy; import static org.junit.Assert.*; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration public class HelloWorldTest { @Autowired HelloWorld helloWorld; private final static Logger logger = LoggerFactory .getLogger(HelloWorldTest. class ); @Test public void test() { logger.debug(helloWorld.greet()); assertEquals(helloWorld.greet(), 'Hello world, from Spring.' ); } } |
Вы бы заметили, что helloWorld в модульном тесте никогда не инициализировался в коде. Это бит магии весны IoC . Чтобы сделать это, мы использовали @RunWith, @ContextConfiguration и @Autowired. И я также дал Spring достаточно информации, чтобы иметь возможность создать экземпляр HelloWorld и затем внедрить его в HelloWorldTest.helloWorld. Кроме того, assertEquals проверяет совсем другое сообщение, чем то, что фактически жестко запрограммировано в классе HelloWorld. Это было сделано в файле XML, упомянутом ниже. Обратите внимание на расположение файла в структуре Maven.
Файл: /src/test/resources/org/academy/HelloWorldTest-context.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<? xml version = '1.0' encoding = 'UTF-8' ?> xmlns:xsi = 'http://www.w3.org/2001/XMLSchema-instance' xmlns:p = 'http://www.springframework.org/schema/p' xsi:schemaLocation='http://www.springframework.org/schema/beans < bean id = 'helloWorld' class = 'org.academy.HelloWorld' > < property name = 'message' value = 'Hello world, from Spring.' /> </ bean > </ beans > |
Есть несколько способов предоставить этот файл конфигурации для модульного тестирования. @RunWith (SpringJUnit4ClassRunner.class) — это хорошая вещь, которую нужно добавить, но она не обязательна . Здесь я привел лишь ванильный подход, который работает в большинстве случаев, но я призываю аудиторию экспериментировать.
Покрытие модульного теста / покрытие кода.
Я немного убежден в жесткой позиции, потому что чертовски легко сообщить о тестовом освещении. Я буду использовать cobertura в этом примере. Вам нужно добавить cobertua в Maven Pom.
Файл: pom.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!-- Reporting --> < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-site-plugin</ artifactId > < version >3.0</ version > < configuration > < reportPlugins > <!-- Reporting on success / failure of unit tests --> < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-report-plugin</ artifactId > < version >2.6</ version > </ plugin > <!-- Reporting on code coverage by unit tests. --> < plugin > < groupId >org.codehaus.mojo</ groupId > < artifactId >cobertura-maven-plugin</ artifactId > < version >2.5.1</ version > < configuration > < formats > < format >xml</ format > < format >html</ format > </ formats > </ configuration > </ plugin > </ reportPlugins > </ configuration > |
И как только вы сделаете это, добавите JUnit и добавите реальный тест JUnit, вам просто нужно запустить
1
|
mvn -e clean install site |
создать красивый отчет о покрытии кода на основе HTML. Этот отчет позволит вам кликнуть по тестируемому исходному коду и дать вам хорошие зеленые пятна для кода, тестируемого модулем, и красные пятна для тех, которые проскользнули через трещины.
логирование
Вы могли бы пройти долгий путь без надлежащей регистрации. Тем не менее, я провел слишком много выходных и ночей, гоняясь за производственными проблемами, когда бизнес дышал мне в голову, желая, чтобы был какой-то способ узнать, что происходит в приложении, вместо того, чтобы угадывать весь мой путь. Сейчас, со зрелым API, таким как slf4j, и стабильной реализацией, такой как logback, разработчику необходимо добавить только одну дополнительную строку на класс, чтобы воспользоваться преимуществами инфраструктуры ведения журналов корпоративного уровня. Просто не имеет смысла не использовать правильную регистрацию с самого начала любого проекта.
Добавьте slf4j и войдите в зависимости от Maven.
Файл: \ pom.xml.
1
2
3
4
5
6
|
<!-- Logging --> < dependency > < groupId >ch.qos.logback</ groupId > < artifactId >logback-classic</ artifactId > < version >${logback.version}</ version > </ dependency > |
Убедитесь, что стандартное ведение журнала Spring, то есть ведение журнала общего пользования, исключено. Если вам интересно, действительно ли logback действительно хорош, я утверждаю, что именно поэтому Spring не выбрал его для начала. В свою защиту, вот ссылка на официальный блог Spring, где говорится: «Если бы мы могли повернуть время вспять и запустить Spring сейчас как новый проект, он использовал бы другую зависимость от журналирования. Вероятно, первым выбором был бы Simple Logging Facade для Java (SLF4J),… ‘
Файл: \ pom.xml.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<!-- Support for testing Spring applications with too TestNG This artifact is generally always defined the integration testing framework and unit testin < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-test</ artifactId > < version >${org.springframework.version}</ version > < scope >test</ scope > < exclusions > < exclusion > < groupId >commons-logging</ groupId > < artifactId >commons-logging</ artifactId > </ exclusion > </ exclusions > </ dependency > |
Предоставить конфигурацию для входа в систему.
Файл: /src/main/resources/logback.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<? xml version = '1.0' encoding = 'UTF-8' ?> < configuration > < appender name = 'CONSOLE' class = 'ch.qos.logback.core.ConsoleAppender' > < encoder > < pattern >%d %5p | %t | %-55logger{55} | %m %n</ pattern > </ encoder > </ appender > < logger name = 'org.springframework' > < level value = 'INFO' /> </ logger > < root > < level value = 'DEBUG' /> < appender-ref ref = 'CONSOLE' /> </ root > </ configuration > |
Наконец, добавьте один магический вкладыш в начале каждого класса, для которого требуется регистрация (это должны быть все классы).
Файл: src / test / java / org / academy / HelloWorldTest.java
1
2
3
4
5
6
|
[...] private final static Logger logger = LoggerFactory .getLogger(HelloWorldTest. class ); [...] logger.debug(helloWorld.greet()); [...] |
Там вы все настроены. Сейчас самое время углубиться в весну.
Удачного кодирования.
Хотите узнать больше?
Вот ссылки на более ранние статьи в этой серии.
Привет мир с весны 3 MVC
Обработка форм с помощью Spring 3 MVC
И, конечно, это очень рекомендуется
Spring 3 Тестирование с помощью JUnit 4.
Запуск юнит-тестов с помощью Spring Framework
@RunWith JUnit4 с обоими SpringJUnit4ClassRunner и параметризованными
Проблема с Юнитом и Весной.
Ссылка: JUnit, Logback, Maven with Spring 3 от нашего партнера JCG Partho в блоге Tech for Enterprise .