Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Junit 5 with Spring Boot: When to use @ExtendWith Spring or Mockito?

I Have the following abstract unit test class that all my concrete unit test classes extend:

@ExtendWith(SpringExtension.class)
//@ExtendWith(MockitoExtension.class)
@SpringBootTest(
    classes = PokerApplication.class,
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public abstract class AbstractUnitTests {

    @MockBean
    public RoundService roundService;

    @MockBean
    public RoundRepository roundRepository;
}

What is the difference between using @ExtendWith(SpringExtension.class) or @ExtendWith(MockitoExtension.class)?

I ask as using either of the annotations seems to make no difference and both work respectively in my code - allowing me to use Junit5. So why do both work?

Concrete test class:

    @DisplayName("Test RoundService")
    public class RoundsServiceTest extends AbstractUnitTests {

        private static String STUB_USER_ID = "user3";

        // class under test
        @InjectMocks
        RoundService roundService;

        private Round round;

        private ObjectId objectId;

        @BeforeEach //note this replaces the junit 4 @Before
        public void setUp() {

            initMocks(this);
            round = Mocks.round();
            objectId = Mocks.objectId();
        }

        @DisplayName("Test RoundService.getAllRoundsByUserId()")
        @Test
        public void shouldGetRoundsByUserId() {

            // setup
            given(roundRepository.findByUserId(anyString())).willReturn(Collections.singletonList(round));

            // call method under test
            List<Round> rounds = roundService.getRoundsByUserId(STUB_USER_ID);

            // asserts
            assertNotNull(rounds);
            assertEquals(1, rounds.size());
            assertEquals("user3", rounds.get(0).userId());
        }
}

Relevant Build.gradle section :

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.2.RELEASE'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    implementation 'junit:junit:4.12'
}

test {
    useJUnitPlatform()
}
like image 637
java12399900 Avatar asked Apr 25 '20 23:04

java12399900


People also ask

Can we use Mockito with JUnit 5?

Mockito provides an implementation for JUnit5 extensions in the library – mockito-junit-jupiter.

What is @ExtendWith @RunWith and their difference?

@RunWith is an old annotation from JUnit 4 to use test runners. If you're using JUnit 5 (Jupiter), you should use @ExtendWith to use JUnit extensions.

What is the use of @ExtendWith SpringExtension class?

Class SpringExtension. SpringExtension integrates the Spring TestContext Framework into JUnit 5's Jupiter programming model. To use this extension, simply annotate a JUnit Jupiter based test class with @ExtendWith(SpringExtension.

What does @ExtendWith annotation do?

The "@ExtendWith" annotation that was seen in the sample story earlier is a markup interface provided by Jupiter. It is a declarative way to register a custom extension on a test class or method. It tells Jupiter's test engine to invoke the custom extension for the given class or method.


2 Answers

What is a Junit Extension

The purpose of Junit 5 extensions is to extend the behavior of test classes or methods

source

Read on Junit 5 Extension Model & @ExtendWith annotation :here

SpringExtension

SpringExtension integrates the Spring TestContext Framework into JUnit 5's Jupiter programming model.

public class SpringExtension
extends Object
implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor, BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver{..}

MockitoExtension

This extension is the JUnit Jupiter equivalent of our JUnit4 MockitoJUnitRunner

public class MockitoExtension
extends java.lang.Object
implements BeforeEachCallback, AfterEachCallback, ParameterResolver{..}

As it can be seen , SpringExtension implements a lot more extensions than MockitoExtension.

Also @SpringBootTest is meta annotated with @ExtendWith(SpringExtension.class) and which means every time your tests are extended with SpringExtension. @MockBean is a Spring test framework annotation and used along with @ExtendWith(SpringExtension.class)

To observe the difference try the following

ExtendWith only MockitoExtension

@ExtendWith(MockitoExtension.class)
class TestServiceTest {

    @MockBean
    TestService service;

    @Test
    void test() {
        assertNotNull(service); // Test will fail
    }

}

ExtendWith only SpringExtension

@ExtendWith(SpringExtension.class)
class TestServiceTest {

    @MockBean
    TestService service;

    @Test
    void test() {
        assertNotNull(service); // Test succeeds
    }

}

ExtendWith with both SpringExtension and MockitoExtension

@ExtendWith(MockitoExtension.class)
@ExtendWith(SpringExtension.class)
class TestServiceTest {

    @MockBean
    TestService service;

    @Test
    void test() {
        assertNotNull(service); // Test succeeds
    }

}

Both works in your case because of the @SpringBootTest annotation for the test class as explained.

To answer the question : When to use @ExtendWith Spring or Mockito? ,

When the test requires a Spring Test Context ( to autowire a bean / use of @MockBean ) along with JUnit 5's Jupiter programming model use @ExtendWith(SpringExtension.class). This will support Mockito annotations as well through TestExecutionListeners.

When the test uses Mockito and needs JUnit 5's Jupiter programming model support use @ExtendWith(MockitoExtension.class)

Hope this helps

like image 120
R.G Avatar answered Oct 22 '22 01:10

R.G


When to use @ExtendWith(SpringExtension.class) or @SpringBootTest?

  • When you use Integration test -@SpringBootTest annotation- or any slice test -@xxxTest annotations- you don't need @ExtendWith(SpringExtension.class) annotation since mentioned annotations include it.

  • If you test @ConfigurationProperties, @Service, @Component annotated class ( not defined in slice test cases - ref:Spring Boot Reference Document Testing/Auto-configured / SLICED Tests item-, you may use @ExtendWith(SpringExtension.class) instead of @SpringBootTest.

Observation: I expect that a test with @ExtendWith(SpringExtension.class) faster than the same test with @SpringBootTest.When I perform a test in Eclipse i observed the reverse.

like image 31
a.lgl Avatar answered Oct 22 '22 01:10

a.lgl