Статьи

JUnit, Logback, Maven с пружиной 3

В этой серии мы уже научились настраивать базовое приложение Spring MVC и научились обрабатывать формы в Spring MVC . Теперь пришло время заняться некоторыми более сложными темами. Однако, прежде чем мы углубимся в более глубокие воды, давайте разберемся с некоторыми основами.

Модульное тестирование

Я не евангелист 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'?>
 
  <bean id='helloWorld' class='org.academy.HelloWorld'>
    <property name='message' value='Hello world, from Spring.' />
  </bean>
</beans>

Есть несколько способов предоставить этот файл конфигурации для модульного тестирования. @RunWith (SpringJUnit4ClassRunner.class) — это хорошая вещь, которую нужно добавить, но она не обязательна . Здесь я привел лишь ванильный подход, который работает в большинстве случаев, но я призываю аудиторию экспериментировать.

Покрытие модульного теста / покрытие кода.

Я не чувствую, что достаточно сказано о важности автоматизированного / полуавтоматического / простого способа составления отчетов о покрытии кода — как для отдельных разработчиков, так и для технических руководителей. Если вы не практикуете TDD религиозно (что, как я уже упоминал ранее, я лично никогда не смог), даже для отдельного разработчика абсолютно невозможно узнать, все ли логические ветви кода охвачены модульным тестом. Я даже не собираюсь говорить о том, как технический руководитель команды / организации будет гарантировать, что его продукт (ы) будет достаточно протестирован. Лично я считаю, что любой программный продукт, который недостаточно протестирован на модульном уровне и не покрыт тестированием, представляет собой неприемлемый риск. Период. По общему признанию немного жесткой позиции, но это — то, как это.

Я немного убежден в жесткой позиции, потому что чертовски легко сообщить о тестовом освещении. Я буду использовать 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. Этот отчет позволит вам кликнуть по тестируемому исходному коду и дать вам хорошие зеленые пятна для кода, тестируемого модулем, и красные пятна для тех, которые проскользнули через трещины.

логирование

Log4j это хорошо, Logback лучше . Только не используйте System.out.println () для регистрации.

Вы могли бы пройти долгий путь без надлежащей регистрации. Тем не менее, я провел слишком много выходных и ночей, гоняясь за производственными проблемами, когда бизнес дышал мне в голову, желая, чтобы был какой-то способ узнать, что происходит в приложении, вместо того, чтобы угадывать весь мой путь. Сейчас, со зрелым 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 .