Java 如何用Mockito模拟对spring托管的@Bean的静态访问?
我有一个Java 如何用Mockito模拟对spring托管的@Bean的静态访问?,java,spring,junit,mockito,spring-boot-test,Java,Spring,Junit,Mockito,Spring Boot Test,我有一个@服务bean,我需要静态访问: @Service public class MyBean implements InitializingBean { private static MyBean instance; @Override public void afterPropertiesSet() throws Exception { instance = this; } public static MyBean get()
@服务
bean,我需要静态
访问:
@Service
public class MyBean implements InitializingBean {
private static MyBean instance;
@Override
public void afterPropertiesSet() throws Exception {
instance = this;
}
public static MyBean get() {
return instance;
}
public String someMethod(String param) {
return "some";
}
}
用法:
@Service
public class OtherService {
public static void makeUse() {
MyBean myBean = MyBean.get();
}
}
问题:当我为使用statMyBean
访问的OtherService
编写集成junit
测试时,实例
变量总是空的
@RunWith(SpringRunner.class)
@SpringBootTest
public class ITest {
@Autowired
private OtherService service;
@MockBean
private MyBean myBean;
@Before
public void mock() {
Mockito.when(myBean.someMethod(any()).thenReturn("testvalue");
}
@Test
public void test() {
service.makeUse(); //NullPointerException, as instance is null in MyBean
}
}
问题:在对spring管理的bean使用此类静态访问时,如何编写集成测试?如果您想影响
@bean
-创建,那么使用@Configuration
@Configuration
public class MyConfig {
@Bean
public MyBean myBean() {
return new MyBean;
}
@Bean
public OtherService otherService () {
return new OtherService(myBean());
}
}
然后嘲弄变得非常容易:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ITest {
@MockBean
private MyBean myBean;
@Autowired
private OtherService service;
@Test
public void test() {
// service is initialised with myBean
...
}
}
当需要更多控制时,您可以选择以下方法。它有时提供比@MockBean更多的控制。在测试中,您可以在调用方法之前轻松地模拟它。这是我喜欢的方式
@Configuration
public class MyConfig {
...
@Bean
public MyBean getMyBean() {
return mock( MyBean.class);
}
@Bean
public OtherService otherService () {
return new OtherService( getMyBean());
}
}
在应用程序中,您可以使用@autowired访问它,并轻松实现方法否决/模拟
@RunWith(SpringRunner.class)
@SpringBootTest
public class AnotherTest {
@Autowired
private MyBean myBean;
@Autowired
private OtherService service;
@Test
public void test() {
when( myBean.method( a, b)).thenReturn( something);
service.doSomething( ....); // with myBean.method() overruled
}
}
我的第一个问题是,当bean的用户也是spring管理的时,为什么要通过静态字段访问bean?您可以通过Spring注入Singleton实例,但不要使用静态单例!!!他们肮脏邪恶!!!如果您的实用程序方法需要一些东西,那么它应该/必须将其作为参数。直接从该util方法访问Springbean是一种肮脏的、破坏性的设计。好吧,您说服了我,在测试期间模拟静态方法可能已经是一种设计味道了。所以我应该重写我的实用程序,要么a)将服务作为附加参数,要么b)不是实用程序,而是服务本身。正确。这是测试的一大优点:一旦测试变得异常复杂,代码气味就更容易找到。