Skip to content

jqwik extension to support testing of Spring and Spring-Boot applications

License

Notifications You must be signed in to change notification settings

jqwik-team/jqwik-spring

Repository files navigation

jqwik Spring Support

This project provides an extension to support testing of Spring and Spring-Boot applications with jqwik.

Table of Contents

How to Install

Gradle

Follow the instructions here and add the following dependency to your build.gradle file:

dependencies {
    implementation("org.springframework:spring-context:5.3.31")
    ...
    testImplementation("net.jqwik:jqwik-spring:0.10.0")
    testImplementation("org.springframework:spring-test:5.3.31")
}

You can look at a sample project using jqwik, Spring Boot and Gradle.

Maven

Follow the instructions here and add the following dependency to your pom.xml file:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.3.31</version>
</dependency>
...
<dependency>
  <groupId>net.jqwik</groupId>
  <artifactId>jqwik-spring</artifactId>
  <version>0.10.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.3.31</version>
  <scope>test</scope>
</dependency>

Supported Spring Versions

You have to provide your own version of Spring or Spring Boot through Gradle or Maven. The jqwik-spring library has been tested with versions:

See supported versions for more details.

Supported JUnit Platform Versions

You need at least version 1.10.1 of the JUnit platform - otherwise strange things could happen. Keep in mind that if you are using Spring Boot you will have to explicitly set the JUnit platform version.

Standard Usage

To enable autowiring of a Spring application context or beans you just have to add @JqwikSpringSupport to your test container class:

import net.jqwik.api.*;
import net.jqwik.api.constraints.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.spring.*;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.test.context.*;

@JqwikSpringSupport
@ContextConfiguration(classes = MySpringConfig.class)
class MySpringProperties {

  @Autowired
  private MySpringBean mySpringBean;

  @Property
  void nameIsAddedToHello(@ForAll @AlphaChars @StringLength(min = 1) String name) {
    String greeting = mySpringBean.sayHello(name);
    Assertions.assertTrue(greeting.contains(name));
  }
}

Configuration and autowiring of values is delegated to Spring's own test framework. Therefore all integration testing annotations can be used. This is also true for standard annotation support.

Lifecycle

Spring will recreate its application context for each annotated class. That means, that

  • Singleton beans will only be created once for all tests of one test container class.
  • Properties and tries within the same class share mutual state of all Spring-controlled beans.

If you want a property to recreate the app context for each try, you have to annotate the property method with @DirtiesContext. Compare the following two properties:

@JqwikSpringSupport
@ContextConfiguration(classes = MySpringConfig.class)
class MySpringProperties {

  @Property(tries = 10)
  void counterIsCountingUp(@Autowired MyCounter counter) {
    counter.inc();
    // Prints out 1, 2, 3 ... 10
    System.out.println(counter.value());
  }

  @Property(tries = 10)
  @DirtiesContext
  void counterIsAlways1(@Autowired MyCounter counter) {
    counter.inc();
    // Prints out 1, 1, 1 ... 1
    System.out.println(counter.value());
  }
}

Support for Jqwik Lifecycle Hooks

The class JqwikSpringLifecycleSupport provides methods that can be used from jqwik lifecycle hooks:

  • getApplicationContext(LifecycleContext) returns an optional of the current Spring application context.

Parameter Resolution of Autowired Beans

Autowired beans will be injected as parameters in example and property methods, in all lifecycle methods and also in the test container class's constructor - if there is only one:

@JqwikSpringSupport
@ContextConfiguration(classes = MySpringConfig.class)
class MyOtherSpringProperties {
    @Autowired
    MyOtherSpringProperties(MySpringBean springBean) {
        Assertions.assertNotNull(springBean);
    }

    @BeforeProperty
    void beforeProperty(@Autowired MySpringBean springBean) {
        Assertions.assertNotNull(springBean);
    }

    @Property
    void beanIsInjected(@Autowired MySpringBean springBean) {
        Assertions.assertNotNull(springBean);
    }
}

Spring JUnit Jupiter Testing Annotations

jqwik's Spring support is trying to mostly simulate how Spring's native Jupiter support works. Therefore, some of that stuff also works, but a few things do not.

Supported Jupiter Test Annotations

Spring Boot

By using @JqwikSpringSupport as described above most - if not all - Spring Boot testing features, e.g. test auto-configuration annotations should work.

Supported Spring / Spring Boot Versions

jqwik-spring 0.12.0

Supports Java 17 and above.

Spring Framework

  • 5.2.15-RELEASE
  • 5.3.31
  • 6.1.0

Spring Boot

  • 2.6.15
  • 2.7.17
  • 3.2.0

jqwik-spring 0.10.0

Supports Java 8 and above.

Spring Framework

  • 5.2.15-RELEASE
  • 5.3.31

Spring Boot

  • 2.6.15
  • 2.7.17

Shortcomings

Nested/Grouped Tests in Old Spring (Boot) Versions

Up to Spring version 5.2.15.RELEASE, which comes with Spring Boot 2.3.12.RELEASE, the Spring extension and configuration is NOT handed down to inner test groups. Also, member variables in the outer instance are not being auto wired even if the inner class has all necessary annotations. This is due to limitations of Spring's own testing framework and cannot be fixed by this library.

Release Notes

0.12.0

  • Added JqwikSpringLifecycleSupport.getApplicationContext()

0.11.0

First version supporting Spring 3.x.

Requires Java 17 or above.

  • Tested with Spring 5.3.31, 6.0.14, 6.1.0
  • Tested with Spring Boot 2.6.15, 2.7.17, 3.0.12, 3.1.5, 3.2.0

0.10.0

Last version supporting Java 8 - 16.

  • Upgrade to jqwik 1.8.2
  • Upgrade to JUnitPlatform 5.10.1
  • Tested with Spring 5.3.31
  • Tested with Spring Boot 2.6.15, 2.7.17

0.9.0

  • Upgrade jqwik 1.6.3
  • Upgrade to JUnitPlatform 5.8.2
  • Tested with Spring 5.3.14
  • Tested with Spring Boot 2.6.2

0.8.2

  • Upgrade jqwik 1.5.6
  • Upgrade to JUnitPlatform 5.8.1
  • Tested with Spring 5.3.11
  • Tested with Spring Boot 2.5.5

0.8.1

  • For Spring >= 5.3.0 test configuration is now "inherited" to nested container classes annotated with @Group.

0.8.0

  • Upgrade to jqwik 1.5.3
  • Tested with more recent versions of Spring and Spring Boot