Friday, 21 April 2017

Spring with JUnit

Testing Controllers

@Runwith(SrpingRunner.class)

Unit test
@Runwith(SrpingRunner.class)
@WebMvcTest(SpecificController.class)

Integration test
It includes all dependencies, and provides a full servlet engine behaviour; meanwhile, load @Controllers,@Services and @Repository; 

@Runwith(SrpingRunner.class)
@SpringBootTest(WebEnvironment =RANDOM_PORT); it provides a real servlet container. 


@ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.

@ActiveProfiles("dev")

@Configuration
@Profile("dev")
public class StandaloneDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}





Testing Services 

How to plan to test @Service components. It is the location of business logic, and typically the priority of the test. 

Which type of test is needed? Unit test? Integration test? Both? 

Every component should be involved in an integration test. 

Not load @Controllers, Only load @Service; connecting to a real data source-test-specific or another staging. 

@Runwith(SpringRunner.class) 
@SpringBootTest(webEnvironment=WebEnvment.NONE) 
It means there is no need to include a servlet dispatcher, a servlet container, and controllers for testing @Service layer.

Difference between @Mock and @MockBean

@Mock comes from Mockito framework; @RunWith(MockitoJUnitRunner.class)

@MockBean comes from SpringBoot. @RunWith(SrpingRunner.class) 





@ExtendWith(SpringExtension.class)
Integrating Spring test context with the JUnit 5. 


Testing Data Acess 

There is no too much achieved from a unit test on the repository layer, so focusing on the integration test. 

@Runwith(SpringRunner.class)

it marks the unit test using the Junit4 framework. 

@DataJpaTest

it marks the test specific to the data access layer. Only loading repository components. 

@AutoConfigureTestDatabase

It is applied to a test class to configure a test database to use instead of any application-defined or auto-configured DataSource.

@TestExecutionListeners

@DatabaseSetup

@DataJpaTest magic explained:

  • @AutoConfigureDataJpa: imports all configuration(components) needed for JPA testing. 
  • @AutoConfigureTestDatabase(replace=Replace.NONE): allow to specify what type of database is used for the test; using an embedded database or pointing to another database external or staging; or a default database already found on the classpath; 
  • @AutoConfigureTestEntityManager: allowing to access the EntityManager. 
  • @Transactional: AOP around the method scope. 
  • more ...

DBUnit framework:

DBUnit is another unit test framework in the Java ecosystem that focuses on aiding the ability to test data access code.
  • Created a DBUnit dataset, in XML
  • Combined features of Junit and DBUnit frameworks. 
  • Creating data scenario without creating date entity classes. 

       <dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.0</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.springtestdbunit</groupId>
<artifactId>spring-test-dbunit</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>

Creating integration test datasets: 

Instruct JUnit to do the following:
not load @Controllers,@Services
Load @Repository and related dependencies
Example:@Entity
Load JPA testing configurations
Load DBUnit testing configuration and dataset, in XML


Test Suites

Smoke Tests: tests that indicate basic system health. 

Iteration Suite: tests that are related to a project iteration.

Feature Suite: Tests that combine testing of several features.

@RunWith(Suite.class)
@Suite.SuiteClasses(
{TestA.class, TestB.class}
)

The CI server test suite shows the following:
  • A systems health check
  • Example: database
  • Settled feature integration test
  • Extensible and flexible overall application architectures status check. 

SpringBoot Test

@SpringBootTest provides features like the followings:

  • Automatically searches for a @SpringBootConfiguration when nested @Configuration class is not used, and no explicit classes are specified.
  • Allows custom env. properties to be defined using the properties attributes.
  • Provides support for different web environment modes, including the ability to start a fully running web server listening on a defined or random port. 
  • Registers a TestRestTemplate and/or WebTestClient bean for use in web tests that are a fully running web server.

Using @SpringBootTest for integration testing

SpringBoot integration test: Spring framework offers a way to wire up loose coupling components within an embedded servlet container, and enabled automated configuration, which is also called the Spring Application Context. In such a sandbox, a developer may test his unit test cases(JUnit), such as sending an Http request to web-service methods and connecting to a database(maybe in memory).

Since Spring 3.2, Spring Mock MVC framework provides a test context. It simulates a servlet container, where an HTTP request can be launched and handled by the controller. By this way, a  controller can be tested as if it is running a production server.


In order to initiate a SpringBoot unit test, you need adding following two annotations on a test class.

@RunWith(SpringRunner.class) it bridges JUnit 4 

@SpringBootTest a number of other annotations are also provided for testing more specific slices of an application. The @SpringBootTest annotation tells Spring Boot to go and look for the main configuration class (one with @SpringBootApplication for instance), and use that to start a Spring application context.

You can use the webEnvironment attribute of @SpringBootTest to further refine how your tests will run:

  • MOCK — Loads a WebApplicationContext and provides a mock servlet environment. Embedded servlet containers are not started when using this annotation. If servlet APIs are not on your classpath this mode will transparently fall back to creating a regular non-web ApplicationContext. Can be used in conjunction with@AutoConfigureMockMvc for MockMvc-based testing of your application.
  • RANDOM_PORT — Loads an EmbeddedWebApplicationContext and provides a real servlet environment. Embedded servlet containers are started and listening on a random port.
  • DEFINED_PORT — Loads an EmbeddedWebApplicationContext and provides a real servlet environment. Embedded servlet containers are started and listening on a defined port (i.e from your application.properties or on the default port 8080).
  • NONE — Loads an ApplicationContext using SpringApplication but does not provide any servlet environment (mock or otherwise).

Using @SpringBootTest for unit testing

'Classes' attribute:

The classes attribute specifies the annotated classes to use for loading an ApplicationContext.
@SpringBootTest classes attribute usage

@SpringBootTest(classes = {EmployeeRepository.class, EmployeeService.class})
public class SpringBootDemoApplicationTests
{  
    @Autowired
    private EmployeeService employeeService;
    //---- tests -----
}





References


Spring Boot Hello World Example – Mustache




No comments:

Can Jackson Deserialize Java Time ZonedDateTime

Yes, but must include JSR310. Thus ZonedDateTime can be deserialized directly from JSON response to POJO field. <dependency> <g...