Mockito使用Spring引导模拟Java @Value

gpnt7bae  于 2022-11-08  发布在  Spring
关注(0)|答案(4)|浏览(425)

你好,我有这个简单的代码为我的Spring Boot项目:

@Component
public class UserRowMapper implements RowMapper<User> {
    @Value("${bug.value}")
    private String id;
    @Value("${wrong.value}")
    private String userName;

    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        return User.builder()
                .id(rs.getInt(id))
                .userName(rs.getString(userName)).build();
    }
}

我想要的是创建一个简单的Mockito测试,它将像这样检查@Value字符串:

@ExtendWith(MockitoExtension.class)
class UserRowMapperTest {
    @Mock
    Environment environment;
    @Mock
    ResultSet resultSet;
    @InjectMocks
    UserRowMapper userRowMapper;

    @Test
    void testMapRow() {
        when(environment.getProperty("user.id")).thenReturn("id");
        when(environment.getProperty("user.userName")).thenReturn("userName");
        try {
            final User user = userRowMapper.mapRow(resultSet, anyInt());

            // check if its ok
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

但是我找不到一种简单的方法来检查我注入的值是否是我所期望的。
有什么主意吗?

mxg2im7a

mxg2im7a1#

不幸的是,Spring的@Value没有模拟机制。但是,根据JavaDoc:
ReflectionTestUtils是一个基于反射的实用程序方法的集合,用于单元和集成测试方案。
在测试涉及以下内容的代码时,设置非公共字段、调用非公共setter方法或调用非公共配置或生命周期回调方法通常是有益的

ReflectionTestUtils.setField(userRowMapper, "id", "my-id-value");
ReflectionTestUtils.setField(userRowMapper, "userName", "my-userName-value");

用于ReflectionTestUtils#setField(Object, String, Object)的JavaDoc。

z31licg0

z31licg02#

iduserName字段添加getter方法,而不是模拟Environment类。

@Component
public class UserRowMapper implements RowMapper<User> {
    @Value("${bug.value}")
    private String id;

    @Value("${wrong.value}")
    private String userName;

    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        return User.builder()
                .id(rs.getInt(getId()))
                .userName(rs.getString(getUserName())).build();
    }

    public String getId() {
        return id;
    }

    public String getUserName() {
        return userName;
    }
}

一边嘲讽:

Mockito.when(userRowMapper.getId()).thenReturn("id");
Mockito.when(userRowMapper.getUserName()).thenReturn("userName");

此外,您还可以使用TestPropertySource注解来提供完全不同的属性文件:

@SpringBootTest
@TestPropertySource(locations = "/application2.properties")
public class TestClassTest {

    @Autowired
    TestClass testClass;

    @Test
    public void test() {
        assertEquals("id", testClass.getId());
    }
}
1tuwyuhd

1tuwyuhd3#

我建议您不要在消费者类上使用内联@Value注解。正如您所看到的,类的可测试性会降低。
您可以通过创建一个@Configuration bean并将其注入到UserRowMapper类中来解决问题。这样,使用DI,您可以在测试中轻松地模拟配置。
参见下面的一个简单的实现。
第一个

kqhtkvqz

kqhtkvqz4#

正如 thepaoloboi 所建议的,使用一个配置类来保存所有的配置。现在,为了测试你的配置是否指向正确的@Value键,你可以创建一个集成测试,只需使用spring加载那个对象,而不加载整个上下文。这样,它就像单元测试一样快。
下面是一个例子:

@ExtendWith(SpringExtension.class)
@Import(UserRowMapperConfiguration.class)
@TestPropertySource(properties = { "user.id=id" , "user.userName=userName"})
class UserRowMapperConfigurationTest {

    @Autowired
    UserRowMapperConfiguration userRowMapperConfiguration;

    @Test
    void test() {
        assertEquals("id",userRowMapperConfiguration.getId());
        assertEquals("userName",userRowMapperConfiguration.getUserName());
    }
}

和配置类:

@Configuration
public class UserRowMapperConfiguration {
    @Value("${bug.value}")
    private String id;

    @Value("${wrong.value}")    
    private String userName;

    public String getId() {
        return id;
    }

    public String getUserName() {
        return userName;
    }
}

相关问题