Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jupiter-tools/spring-boot-extensions

A lot of JUnit5 Extensions to work with Spring Boot.
https://github.com/jupiter-tools/spring-boot-extensions

Last synced: 2 months ago
JSON representation

A lot of JUnit5 Extensions to work with Spring Boot.

Awesome Lists containing this project

README

        

:toc: preamble

# JUnit5 Spring Boot Extensions

image:https://travis-ci.com/jupiter-tools/spring-boot-extensions.svg?branch=master["Build Status", link="https://travis-ci.com/jupiter-tools/spring-boot-extensions"]
image:https://codecov.io/gh/jupiter-tools/spring-boot-extensions/branch/master/graph/badge.svg[link ="https://codecov.io/gh/jupiter-tools/spring-boot-extensions"]

## Database specific tests

image:./images/jpa-containers.png[jpa containers extension scheme]

### TraceSql Extension

Provide you an ability to check SQL statement execution after tests.
You need to add the next dependency:

[source,xml]
----

com.jupiter-tools
spring-test-jpa
0.2

----

And now, you can assert a count of insert operations after save an entity:

[source, java]
----
@ExtendWith(TraceSqlExtension.class)
@ExtendWith(SpringExtension.class)
@SpringBootTest
class TraceSqlExtensionTest {

@Autowired
private FooRepository fooRepository;

@Test
void testInsert() {
// Act
fooRepository.save(new Foo("any data"));
// Assert
AssertSqlCount.assertInsertCount(1);
}
}
----

Also, you can use annotation on the test case to assert the expected count of executed queries:

[source, java]
----
@Test
@ExpectedSqlQuery(type = INSERT, count = 1)
void testInsert() {
fooRepository.save(new Foo("data"));
}

@Test
@ExpectedSqlQuery(type = SELECT, count = 1)
void testSelect() {
fooRepository.findAll();
}
----

### PostgreSQL Extension

To run the docker postgres image by the test-containers library
in your integration test, you can use PostgresTcExtension.

[source,xml]
----

com.jupiter-tools
spring-test-postgres
0.2

----

Let's try to execute a stored procedure specific to PostgreSQL:

[source, java]
----
@DataJpaTest
@ExtendWith(SpringExtension.class)
@ExtendWith(PostgresTcExtension.class)
@ExtendWith(TraceSqlExtension.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class PostgresTcExtensionTest {

@PersistenceContext
private EntityManager entityManager;

@Test
@Sql("/stored_functions/test_func.sql")
void testStoredFunc() {
// Arrange
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("rnd");
// Act
query.execute();
// Assert
List resultList = query.getResultList();
int rnd = (int) resultList.get(0);
Assertions.assertThat(rnd).isEqualTo(123);
}
}
----

This library provides a wide system of meta-annotations to
simplified writing integration test's configuration.

For example, you can write:

[source, java]
----
@EnablePostgresDataTest
class EnablePostgresDataTestTest {
...
}
----

instead of:

[source, java]
----
@DataJpaTest
@ExtendWith(SpringExtension.class)
@ExtendWith(PostgresTcExtension.class)
@ExtendWith(TraceSqlExtension.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class PostgresTcExtensionTest {
...
}
----

you can see at whole postgres annotation system at the next picture::

image:./images/pg-annotations.png[postgres annotation system]

You can build a necessary test configuration by using annotations which you need. Meta-annotations is a beautiful mechanism which will you a making configuration in a declarative style.

### MySql Extension

MySqlTcExtension runs the mysql docker image and set spring properties
in the configuration to use this datasource in tests.

[source,xml]
----

com.jupiter-tools
spring-test-mysql
0.2

----

You can use this extension by the applying of `EnableMySqlTestContainersExtension` annotation or
you can use `@EnableMySqlDataTest` to write a test with the DataJpa context configuration:

[source, java]
----
@EnableMySqlDataTest
class EnableMySqlDataTestTest {

@Autowired
private FooRepository repository;

@Test
@Commit
@DataSet(cleanBefore = true, cleanAfter = true)
@ExpectedDataSet(value = "/datasets/expected.json", ignoreCols = "ID")
void testCreate() throws Exception {
repository.saveAndFlush(new Foo("any data"));
}
}
----

As well as for the PostgreSQL in this library there is a system of meta-annotations for the MySql:

image:./images/mysql-annotations.png[mysql annotation system]

## Messaging systems

image:./images/jms.png[messaging system annotations]

### RabbitMq Extension

`RabbitMqTcExtension` runs the RabbitMq docker image by the TestContainers library
and configure SpringBoot properties to work with this container.

[source,xml]
----

com.jupiter-tools
spring-test-rabbitmq
0.2

----

Now we can run RabbitMq in tests and send a message in a real queue:

[source, java]
----
@SpringBootTest
@ExtendWith(SpringExtension.class)
@ExtendWith(RabbitMqTcExtension.class)
class EnableRabbitMqTestTest {

@Autowired
private AmqpTemplate amqpTemplate;

@Test
void testSend() {
amqpTemplate.convertAndSend("test-queue", "123");
...

}
}
----

As well as with database specific tests, in this case, you can use meta-annotation to write tests more pragmatic:

[source, java]
----
@EnableRabbitMqTest
class EnableRabbitMqTestTest {
...
}
----

Also, you can assert the sending of messages in the selected queue:

[source, java]
----
@EnableRabbitMqTest
public class ExpectedMessageTest {

@Autowired
private AmqpTemplate amqpTemplate;

@Test
@ExpectedMessage(queue = "test-queue", message = "123")
void testSend() throws InterruptedException {
amqpTemplate.convertAndSend("test-queue", "123");
}
}
----

Also, you can assert the receiving of multiple messages:

[source, java]
----
@Autowired
private AmqpTemplate amqpTemplate;

@Test
@ExpectedMessages(queue = "test-queue", <1>
messagesFile = "/datasets/expected_messages.json") <2>
void testSendListOfMessages() {
// first type:
amqpTemplate.convertAndSend("test-queue", new Foo("123"));
// second type:
amqpTemplate.convertAndSend("test-queue", new Bar("AAA",1));
amqpTemplate.convertAndSend("test-queue", new Bar("BBB",2));
amqpTemplate.convertAndSend("test-queue", new Bar("CCC",3));
}
----
<1> queue name
<2> file with expected messages in JSON format

Content of the `expected_messages.json` :
[source,json]
----
{
"com.jupiter.tools.spring.test.rabbitmq.extension.pojo.Foo": [
{
"value":"123"
}
],
"com.jupiter.tools.spring.test.rabbitmq.extension.pojo.Bar":[
{
"name":"AAA",
"count":1
},
{
"name":"BBB",
"count":2
},
{
"name":"CCC",
"count":3
}
]
}
----

### ActiveMq Extension

You can run the ActiveMq docker image by the using of `EnableActiveMqTestContainers` annotation.

You need to use the next dependency:

[source,xml]
----

com.jupiter-tools
spring-test-activemq
0.2

----

image:./images/activemq-annotations.png[activemq annotations]

If you need to check a sending of messages then you can use the `ExpectedMessage` annotation:

[source, java]
----
@SpringBootTest
@EnableActiveMqTest
public class SendMessageTest {

@Autowired
private JmsTemplate jmsTemplate;

@Test
@ExpectedMessage(queue = "test-queue", message = "123")
void testSend() {
jmsTemplate.convertAndSend("test-queue", "123");
}

@TestConfiguration
public static class TestConfig {
@Bean
public Queue testQueue() {
return new Queue("test-queue");
}
}
}
----

Also, you can assert the receiving of multiple messages:

[source, java]
----
@Test
@ExpectedMessages(queue = "test-queue", <1>
messagesFile = "/datasets/expected_messages.json") <2>
void testSendListOfMessages() {
// first type:
jmsTemplate.convertAndSend("test-queue", new Foo("123"));
// second type:
jmsTemplate.convertAndSend("test-queue", new Bar("AAA",1));
jmsTemplate.convertAndSend("test-queue", new Bar("BBB",2));
jmsTemplate.convertAndSend("test-queue", new Bar("CCC",3));
}
----
<1> queue name
<2> file with expected messages in JSON format

Content of the `expected_messages.json` :
[source,json]
----
{
"com.jupiter.tools.spring.test.activemq.extension.expected.Foo": [
{
"value":"123"
}
],
"com.jupiter.tools.spring.test.activemq.extension.expected.Bar":[
{
"name":"AAA",
"count":1
},
{
"name":"BBB",
"count":2
},
{
"name":"CCC",
"count":3
}
]
}
----

## Embedded Web Server

Let's consider the next microservice based application:

image:./images/embedded-web.png[embedded web services tests]

You can test inter-service communication by the running an embedded
web server with a mocked external controller and send HTTP requests to this server.

[source,xml]
----

com.jupiter-tools
spring-test-web
0.2

----

Let's test requesting to the template-service by the using of embedded server:

[source, java]
----
@EnableEmbeddedWebServerTest <1>
@RedirectRibbonToEmbeddedWebServer("template-service") <2>
class RedirectRibbonExtensionTest {

@Autowired
private RestTemplate restTemplate;

@Test
void testRedirect() {
// Act
String result = restTemplate.getForObject("http://template-service/templates/{template}",
String.class,
"balance-template");
// Assert
assertThat(result).isEqualTo("{user} balance = {value}");
}

@TestConfiguration
public static class TestCfg {

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}

@RestController
@RequestMapping("/templates")
public class TestApi {

@GetMapping("/{template}")
public String getLength(@PathVariable("template") String template) {
return "{user} balance = {value}";
}
}
}
}
----
<1> bind the embedded server to an available TCP-port
<2> resolve the client name("template-service") to an embedded server url

If you want to run different web servers in one test suite
then you need to use a different port to each server.
And you need to be sure that selected port is available.

Annotation `EnableEmbeddedWebServerTest` bind a random available TCP port to the server.port property of the Spring Framework.

`RedirectRibbonToEmbeddedWebServer` redirects all requests from any ribbon
clients to embedded server, by default (if you don't set the value of this annotation).

## Examples

https://github.com/jupiter-tools/spring-boot-extensions-demo