无法注入测试类中的静态字段

问题描述 投票:0回答:1

我尝试测试一下。注意它是一个接口,所以我要测试 Spring 为我编写的类(作为练习,我正在学习测试)

package pp.spring_bootstrap.dao;


import org.springframework.data.jpa.repository.JpaRepository;
import pp.spring_bootstrap.models.Role;

import java.util.List;

public interface RoleDao extends JpaRepository<Role, Long> {
    Role findByAuthority(String authority);

    List<Role> findByAuthorityOrAuthority(String auth1, String auth2);
}
@Entity
@Table(name = "roles")
@Getter
@Setter
@EqualsAndHashCode
public class Role implements GrantedAuthority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(name = "role", nullable = false, unique = true)
    private String authority;
    @ManyToMany(mappedBy = "authorities")
    @EqualsAndHashCode.Exclude
    private Set<User> userList;

    public Role() {
    }

    public Role(String authority) {
        this.authority = authority;
    }

    @Override
    public String getAuthority() {
        return authority;
    }

    // toString()
}

这是我的测试课:

package pp.spring_bootstrap.dao;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import pp.spring_bootstrap.models.Role;

import java.util.List;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@SpringBootTest
class RoleDaoTest {
    static RoleDao roleDao;
    static final Role USER = new Role("USER");
    static final Role ADMIN = new Role("ADMIN");
    @Autowired
    /*could be public, doesn't matter */ void setRoleDao(RoleDao roleDao) {
        RoleDaoTest.roleDao = roleDao;
    }
    @BeforeAll
    static void addSampleRows() {
        roleDao.saveAll(List.of(USER, ADMIN));
    }
    @Test
    void findByAuthority() {
        assertThat(roleDao.findByAuthority("USER")).isEqualTo(USER);
    }

    @Test
    void findByAuthorityOrAuthority() {
        assertThat(roleDao.findByAuthorityOrAuthority("USER", "ADMIN")).asList().contains(USER, ADMIN);
    }
}

用于测试的

properties
文件(在测试资源根目录内):

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

我得到了 NPE,因为没有注入任何东西。为什么?

java.lang.NullPointerException: Cannot invoke "pp.spring_bootstrap.dao.RoleDao.saveAll(java.lang.Iterable)" because "pp.spring_bootstrap.dao.RoleDaoTest.roleDao" is null

我不能用 setter 注入

static
字段吗?我认为这是你用来注入静态的技巧

java spring-boot testing h2
1个回答
0
投票

您有多种选择可以让您的代码正常工作。第一个是使用

@BeforeEach
方法,不需要静态签名并确保在每个测试用例之前执行所需的规则。

@Autowired
private RoleDao roleDao;

@BeforeEach
void addSampleRows() {
    roleDao.saveAll(List.of(USER, ADMIN));
}

或者,您可以添加

@TestInstance
注释。 JUnit 5 中的
@TestInstance
注释用于确定带注释的测试类的测试实例的生命周期。默认情况下它是
PER_METHOD
。如果将其更改为
PER_CLASS
@BeforeAll
将不再需要是静态的:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class RoleDaoTest {

将为所有测试方法创建测试类的单个实例。这样,您就可以在这些方法中使用依赖注入而不会出现任何问题。

你的课程将如下所示:

@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class RoleDaoTest {

    @Autowired
    private RoleDao roleDao;

    static final Role USER = new Role("USER");
    static final Role ADMIN = new Role("ADMIN");

    @BeforeAll
    void init() {
        roleDao.saveAll(List.of(USER, ADMIN));
    }

    @Test
    void findByAuthority() {
        assertThat(roleDao.findByAuthority("USER")).isEqualTo(USER);
    }

    @Test
    void findByAuthorityOrAuthority() {
        assertThat(roleDao.findByAuthorityOrAuthority("USER", "ADMIN")).containsExactlyInAnyOrder(USER, ADMIN);
    }
}

通过使用

PER_CLASS
生命周期
roleDao
被正确注入。
init()
方法(现在是实例方法而不是静态的)在所有测试方法之前运行一次。 您可以在
@BeforeAll
中使用依赖注入,没有任何并发症。 但是,请记住,
PER_CLASS
生命周期意味着所有测试方法共享测试类的相同实例。这可能会在测试方法之间引入副作用,因此如有必要,请务必确保重置
@BeforeEach
@AfterEach
方法中的任何共享状态。

© www.soinside.com 2019 - 2024. All rights reserved.