Модульное тестирование
Я не евангелист 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)@ContextConfigurationpublic 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 .