Search code examples
springjunit-jupiterjgiven

Is it possible to combine 'JGiven Spring' with 'JGiven JUnit 5'?


Unfortunatly spring beans are not autowired with my approach. I used version 0.17.0 of JGiven.

The following Test fails with a NullPointerException because spring bean 'messageService' in class HelloWorldStage is null.

Gradle:

testCompile group: 'com.tngtech.jgiven', name: 'jgiven-junit5', version: '0.17.0'
testCompile group: 'com.tngtech.jgiven', name: 'jgiven-spring', version: '0.17.0'

Test Class:

import com.tngtech.jgiven.annotation.ScenarioStage;
import com.tngtech.jgiven.integration.spring.EnableJGiven;
import com.tngtech.jgiven.junit5.JGivenExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@SpringBootTest(classes = {HelloWorldTest.class})
@Configuration
@EnableJGiven
@ComponentScan(basePackages = "sample.jgiven.*")
@ExtendWith(JGivenExtension.class)
class HelloWorldTest {

    @ScenarioStage
    private HelloWorldStage helloWorldStage;

    @Test
    void sayHello() {
        helloWorldStage
                .given().recipient("Bob")
                .when().sendMessage()
                .then().answer();
    }
}

Stages:

import com.tngtech.jgiven.Stage;
import com.tngtech.jgiven.annotation.Quoted;
import com.tngtech.jgiven.annotation.ScenarioState;
import com.tngtech.jgiven.integration.spring.JGivenStage;
import org.springframework.beans.factory.annotation.Autowired;

@JGivenStage
class HelloWorldStage extends Stage<HelloWorldStage> {

    @Autowired
    private MessageService messageService;

    @ScenarioState
    private String recipient;

    HelloWorldStage recipient(@Quoted String name) {
        this.recipient = name;
        return self();
    }

    public HelloWorldStage sendMessage() {
        return self();
    }

    public String answer() {
        return messageService.createMessage(recipient);
    }
}

Spring Bean:

import org.springframework.stereotype.Service;

@Service
public class MessageService {

    public String createMessage(String recipient) {
        return "Hello " + recipient;
    }
}

Solution

  • Gradle:

    testCompile group: 'com.tngtech.jgiven', name: 'jgiven-junit5', version: '0.17.0'
    testCompile group: 'com.tngtech.jgiven', name: 'jgiven-spring', version: '0.17.0'
    testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.3.2'
    testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.1.1.RELEASE'
    

    Class under test:

    package mypackage;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MessageService {   
        public String createMessage(String recipient) {
            return "Hello " + recipient;
        }
    }
    

    Spring configuration:

    package mypackage;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import com.tngtech.jgiven.integration.spring.EnableJGiven;
    
    @EnableJGiven
    @Configuration
    @ComponentScan(basePackages = {"mypackage"})
    public class SpringConfig {
    }
    

    Stage class:

    package mypackage;
    import org.springframework.beans.factory.annotation.Autowired;
    import com.tngtech.jgiven.Stage;
    import com.tngtech.jgiven.annotation.ScenarioState;
    import com.tngtech.jgiven.integration.spring.JGivenStage;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    @JGivenStage
    class HelloWorldStage extends Stage<HelloWorldStage> {
    
        @Autowired
        private MessageService messageService;
    
        @ScenarioState
        private String recipient;
    
        @ScenarioState
        private String answer;
    
        HelloWorldStage recipient(String name) {
            this.recipient = name;
            return self();
        }
    
        public HelloWorldStage sendMessage() {
            answer = messageService.createMessage(recipient);
            return self();
        }
    
        public void answerIs(String expectedAnswer) {
            assertThat(answer).isEqualTo(expectedAnswer);
        }
    }
    

    Test:

    package mypackage;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit.jupiter.SpringExtension;
    
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = { SpringConfig.class })
    public class HelloWorldTest {
    
        @Autowired
        private HelloWorldStage helloWorldStage;
    
        @Test
        void someTest() {
            helloWorldStage
                    .given().recipient("World")
                    .when().sendMessage()
                    .then().answerIs("Hello World");
        }
    }