Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何用Mockito模拟对spring托管的@Bean的静态访问?_Java_Spring_Junit_Mockito_Spring Boot Test - Fatal编程技术网

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();
    }
}
问题:当我为使用stat
MyBean
访问的
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)不是实用程序,而是服务本身。正确。这是测试的一大优点:一旦测试变得异常复杂,代码气味就更容易找到。