如果在我们正在测试的方法中使用新关键字声明实例,我们可以模拟它吗?

Posted

技术标签:

【中文标题】如果在我们正在测试的方法中使用新关键字声明实例,我们可以模拟它吗?【英文标题】:Can we mock the instance if it declared with new key word that is inside the method we are testing? 【发布时间】:2020-10-01 05:08:25 【问题描述】:

我是 Mockito 和 Junit 的新手,我正在使用 Spring Boot

我想知道,如果在我们正在测试的方法中使用 new 关键字声明实例,我们可以模拟它吗?

例如:

@Service 
class A 

    @Autowired
    X x;

    @Autowired
    Y y;

    public void testMe()
        imCommunicatingWithSomeRestClient();
    

    private void imCommunicatingWithSomeRestClient()
        String body="";
        MyRestClient client=new MyRestClient(iTakeUrlNeedsToHit); //no arg constructor not exist and suppose this is the method of some Core jar project
        client.callDataRest(HTTP.GET,body)
    


虽然我想模拟它,但我已经尝试了所有 @Spy @Mock@InjectMocks 来检查它的行为是否会有所不同,但这些都不适合我,因为它总是创建一个新对象并调用真正的方法。

所以我稍微改变了方法,并使用 BeanFactory 来代替 new 我将其替换为:

MyRestClient client=beanFactory.getBean(MyRestClient.class,jobDataRestUrl); 

所以我有这些问题:

    上面已经问过(如果我们模拟实例,如果它使用我们正在测试的方法内部的 new 关键字声明)。

    如果我当前的项目是Spring Boot项目并且MyRestClient在核心写的jar里面。标准是否说我不应该由 Bean Factory 创建它,因为我认为我应该这样做并让 Spring 处理它

    我什至尝试过反射,但它似乎也不适用于在方法内使用 new 关键字创建的实例,而不是在类级别。

【问题讨论】:

【参考方案1】:

您当前的设置无法有效测试。您仍然可以使用许多奇怪的解决方法来做到这一点,但仍然不推荐。这是你可以做的;首先,你的类中不应该有任何类型的依赖初始化(比如new MyRestClient(...))。因此,将 REST 客户端移动到属性级别并通过构造函数将其注入。

@Service
class A 
    private final X x;
    private final Y y;
    private final MyRestClient restClient;

    public A (X x, Y y, MyRestClient restClient) 
        this.x = x;
        this.y = y;
        this.restClient = restClient;
    

    public void testMe() 
        imCommunicatingWithSomeRestClient();
    

    private void imCommunicatingWithSomeRestClient() 
        String body = "";
        restClient.callDataRest(GET, body);
    

由于您使用的是 Spring,您可以创建 REST 客户端的 bean 并将端点 URL 移动到外部属性。

class Config 

    @Bean
    public MyRestClient myRestClient(@Value("$property.name") String url) 
        return new MyRestClient(url);
    


最后,您可以轻松地模拟该 REST 客户端的行为。

@ExtendWith(MockitoExtension.class)
class TestA 

    @Mock
    private X x;

    @Mock
    private Y y;

    @Mock
    private MyRestClient restClient;

    @InjectMocks
    private A a;

    // your tests...

【讨论】:

所以最后我们不是通过spring创建了@Bean bean吗? 在应用程序本身中,是的,bean 是由 Spring 创建的,但在测试中它是一个模拟

以上是关于如果在我们正在测试的方法中使用新关键字声明实例,我们可以模拟它吗?的主要内容,如果未能解决你的问题,请参考以下文章

抽象类

我们可以声明一个抽象方法来返回抽象超类中的子类对象而不需要新的实例化吗?

表单的新实例覆盖现有表单变量声明

Java面向对象之抽象与接口

使用selenium在java中使用testng进行并行测试

C# 嵌套对象属性