java · 2024-03-31 0

@RunWith、@ExtendWith、@SpringBootTest 区别及自定义扩展

一、Junit4 与 @RunWith

@RunWith 是 Junit4 的注解,@RunWith 可以指定 ClassRunner

1.pom

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

2.自定义 ClassRunner

public class CustomJUnit4ClassRunner extends BlockJUnit4ClassRunner {

    public CustomJUnit4ClassRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected Statement withBeforeClasses(Statement statement) {
        Statement result = super.withBeforeClasses(statement);
        System.out.println("- - - custom beforeClass - - -");
        return result;
    }

    @Override
    protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
        Statement result = super.withBefores(method, target, statement);
        System.out.println("- - - custom before - - -");
        return result;
    }
}

3.测试类

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

// JUnit 4
// @RunWith 可以指定 ClassRunner
// 对于4.4之前版本的 JUnit,默认的 Runner 是 Junit4ClassRunner
// 对于4.4之后版本的 JUnit,默认的 Runner 是 BlockJunit4ClassRunner
// @RunWith(MockitoJUnitRunner.class),配合 Mockito 来做单元测试,这时可使用 @Mock、@InjectMocks、@Spy 注解来配合写单元测试用例
// @RunWith(SpringJUnit4ClassRunner.class),配合 SpringBoot 来做单元测试
@RunWith(CustomJUnit4ClassRunner.class)
public class JUnit4Test {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("- - - @BeforeClass - - -");
    }

    @Before
    public void before() {
        System.out.println("- - - @Before - - -");
    }

    @Test
    public void test1() {
        System.out.println("Test 1");
    }

    @Test
    public void test2() {
        System.out.println("Test 2");
    }

    @Test
    public void test3() {
        System.out.println("Test 3");
    }

    @Test
    public void test4() {
        System.out.println("Test 4");
    }
}

结果:

- - - custom beforeClass - - -
- - - @BeforeClass - - -
- - - custom before - - -
- - - @Before - - -
Test 1
- - - custom before - - -
- - - @Before - - -
Test 2
- - - custom before - - -
- - - @Before - - -
Test 3
- - - custom before - - -
- - - @Before - - -
Test 4

二、Junit5 与 @ExtendWith

@ExtendWith 是 Junit5 的注解,用于注册扩展器,拦截测试方法

1.pom

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

2.自定义 Extension

public class CustomJUnit5BeforeAllExtension implements BeforeAllCallback {

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        System.out.println("- - - custom beforeAll - - -");
    }
}
public class CustomJUnit5BeforeEachExtension implements BeforeEachCallback {
    @Override
    public void beforeEach(ExtensionContext context) throws Exception {
        System.out.println("- - - custom beforeEach - - -");
    }
}

3.测试类

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.extension.ExtendWith;

// JUnit 5
// @ExtendWith 用于注册扩展器,拦截测试方法
// @ExtendWith(MockitoExtension.class),配合 Mockito 来做单元测试,这时可使用 @Mock、@InjectMocks、@Spy 注解来配合写单元测试用例
// @ExtendWith(SpringExtension.class),配合 SpringBoot 来做单元测试,同时使用 @MockBean 来配合写单元测试用例
@ExtendWith({CustomJUnit5BeforeEachExtension.class, CustomJUnit5BeforeAllExtension.class})
public class JUnit5Test {

    @BeforeAll
    public static void beforeAll() {
        System.out.println("- - - @BeforeAll - - -");
    }

    @BeforeEach
    public void beforeEach() {
        System.out.println("- - - @BeforeEach - - -");
    }

    @Test
    public void test1() {
        System.out.println("Test 1");
    }

    @Test
    public void test2() {
        System.out.println("Test 2");
    }

    @Test
    @EnabledOnOs(OS.LINUX)
    public void test3() {
        System.out.println("Test 3");
    }

    @Test
    @EnabledOnOs(OS.WINDOWS)
    public void test4() {
        System.out.println("Test 4");
    }
}

结果:

- - - custom beforeAll - - -
- - - @BeforeAll - - -
- - - custom beforeEach - - -
- - - @BeforeEach - - -
Test 1
- - - custom beforeEach - - -
- - - @BeforeEach - - -
Test 2
- - - custom beforeEach - - -
- - - @BeforeEach - - -
Test 3

三、@SpringBootTest

1.pom

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!-- spring-boot-starter-test 有 JUnit5 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

2.java

public interface StudentDao {

    void say();
}

@Component
public class StudentDaoImpl implements StudentDao {

    @Override
    public void say() {
        System.out.println("- - - StudentDaoImpl say() - - -");
    }
}

public interface StudentService {

    void say();
}

@Component
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentDao studentDao;

    @Override
    public void say() {
        System.out.println("- - - StudentServiceImpl say() - - -");
        studentDao.say();
    }
}

启动类

@SpringBootApplication
public class Boot {

    public static void main(String[] args) {
        SpringApplication.run(Boot.class, args);
    }
}

3.测试类

// @RunWith(SpringRunner.class) // junit4 使用, junit5 不需要加上
@SpringBootTest // @SpringBootTest 注解包含 @ExtendWith(SpringExtension.class)
public class SpringBootJunitTest {

    @Autowired
    private StudentService studentService;

    @org.junit.jupiter.api.Test
    // @org.junit.Test
    public void testSay() {
        studentService.say();
    }
}

结果:

- - - StudentServiceImpl say() - - -
- - - StudentDaoImpl say() - - -