spring - 在 Autowired 之前如何配置模拟?
问题描述
我想在测试之前使用 Mockito 设置模拟数据。但是,自动装配发生在之前,@Before
所以我的预期数据存在的测试丢失了。有办法解决吗?
@RunWith(SpringRunner.class)
@ContextConfiguration(
classes = {
Foo.class
}
)
public class FooTest {
@MockBean
final Programs programs;
@Autowired
final Foo foo;
@Before
public void setPrograms() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
}
@Test
public void foo() {
assertThat(foo.getBlah()).isNotEmpty();
}
}
interface Programs {
List<String> findAll();
}
class Foo {
// I have more complicated structures than a list, for example only.
private List<String> blah;
@Autowired
private Programs programs;
public List<String> getBlah() { return blah; }
@PostConstruct
public void init() {
blah = programs.findAll();
}
}
解决方案
按照你的例子,我开发了下一个:
public interface Programs {
List<String> findAll();
}
public class Foo {
// I have more complicated structures than a list, for example only.
private List<String> blah;
@Autowired
private Programs programs;
public List<String> getBlah() { return blah; }
@PostConstruct
public void init() {
blah = programs.findAll();
}
}
以上等于您提供的代码。现在,“变化”:
// Only for testing purpose, you can use any of your own ones
public class ProgramsImpl implements Programs {
@Override
public List<String> findAll() {
return asList("1", "2", "3");
}
}
和junit测试:
@RunWith(SpringRunner.class)
@ContextConfiguration(
classes = {
Foo.class, ProgramsImpl.class
}
)
public class FooTest {
@SpyBean
Programs programs;
@Autowired
Foo foo;
@Before
public void prepare() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
this.foo.init();
}
@Test
public void foo() {
assertEquals(asList("A", "B", "C"), foo.getBlah());
}
}
上面的测试按预期工作,也就是说,尽管ProgramsImpl.findAll
返回"1", "2", "3"
的when
子句包含的子句会用你自己的子句覆盖它。
但是,您可能会发现真的@PostConstruct
被调用了两次:一次是由于,@Autowire
第二次是由于init
。
如果你想避免它,你需要在你的测试中删除并创建你的内部@Autowire
实例(使用“普通构造函数”)。例如:foo
@Before
public class Foo {
...
private Programs programs;
@Autowired
public Foo(Programs programs) {
this.programs = programs;
}
...
}
@RunWith(SpringRunner.class)
@ContextConfiguration(
classes = {
ProgramsImpl.class
}
)
public class FooTest {
@SpyBean
Programs programs;
Foo foo;
@Before
public void prepare() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
this.foo = new Foo(programs);
this.foo.init();
}
@Test
public void foo() {
assertEquals(asList("A", "B", "C"), foo.getBlah());
}
}
推荐阅读
- java - 我无法遍历父窗口到子窗口
- c - 在块内获取全局变量时,“extern”会做什么?(使用相同名称定义的不同变量)
- python - 如何将列中的所有日期转换为行系列而不干扰其下方的行
- c# - 查找引发我的 itemcheck 的 listview 事件
- css - CSS 跨浏览器动画技巧(液体/粘糊糊的复选框动画)
- amazon-s3 - 流水线 CI/CD 操作仅对更改的文件
- c++ - C++ 中没有声明匹配
- android - 是否可以从 iOS / Android 应用程序中抓取本地存储数据?
- google-cloud-platform - 如何手动构建到 BiqQuery 云控制台的动态链接
- azure-data-explorer - 使用 azure sdk 获取 azure-dataexplorer 集群使用的 azure 资源