In Java unit testing, how to mock the variables that are not injected but created inside the to-be-tested class?

huangapple go评论72阅读模式
英文:

In Java unit testing, how to mock the variables that are not injected but created inside the to-be-tested class?

问题

例如,要测试的类如下所示:

public class toBeTested {
    private Object variable;

    public toBeTested(){
        variable = someFactory();         // 如果这个 someFactory() 发送网络请求怎么办?
                                          // 在测试中,我能够在不调用 someFactory() 的情况下模拟 "variable" 吗?
    }

    public void doSomething(){
        ...
        Object returnedValue = variable.someMethod();  // 在测试中,当 "variable" 是一个未注入的私有实例变量时,
                                                       // 我能够模拟这个 someMethod() 方法的行为吗?
        
        Object localVariable = new SomeClass();        // 我能在测试中模拟这个 "localVariable" 吗?
        ...
    }
}

我的问题如上面的评论所述。

简而言之,如何模拟未注入但在待测试类内部创建的变量?

提前致谢!

英文:

For example, the class to be tested is

public class toBeTested {
    private Object variable;

    public toBeTested(){
        variable = someFactory();         // What if this someFactory() sends internet request? 
                                          // Can I mock "variable" without calling 
                                          // someFactory() in testing?
    }

    public void doSomething(){
        ...
        Object returnedValue = variable.someMethod();  // In testing, can I mock the behavior of 
                                                       // this someMethod() method when 
                                                       // "variable" is a private instance 
                                                       // variable that is not injected? 
        
        Object localVariable = new SomeClass();        // Can I mock this "localVariable" in 
                                                       // testing?
        ...
    }
}

My questions are as stated in the comments above.

In short, how to mock the variables that are not injected but created inside the to-be-tested class?

Thanks in advance!

答案1

得分: 2

你的问题更多涉及设计,你的类设计是错误的,而且不具备可测试性。在已开发出方法和类之后编写单元测试并不容易(有时甚至根本不可能)。实际上,测试驱动开发(TDD)的一个巨大优势是,它帮助开发者以可测试的方式开发其组件。

如果最初就编写了测试,你的类不会以这种方式被开发。事实上,当为组件编写测试时,不可避免的一件事情就是重构。为了将你的组件重构为可测试的组件,你应该将工厂作为参数传递给类的构造函数。

至于局部变量:

这实际取决于你的情况以及对单元(这里指的是doSomething方法)的预期。如果这是一个你希望方法在其任务中创建的变量,并且每次调用都应基于方法中的某些逻辑创建它,那么将其保留在那里是没有问题的。但如果它为方法提供了其他逻辑,并且可以作为参数传递给你的类,那么你可以将它作为类构造函数的参数传递。

还有一件事,在进行重构时要小心,因为会有许多其他组件使用你的组件,你应该一步一步地进行重构,不应改变方法的逻辑。

英文:

Your question is more about the design, the design of your class is wrong and it is not testable, It is not easy (and sometimes it is not possible at all) to write a unit test for a method and class that have been developed before. Actually one of the great benefit of TDD(Test Driven Development) is that it helps the developer to develop their component in a testable way.

Your class would have not been developed this way if its test had been written first. In fact one of the inevitable thing that you should do when you are writing test for your component is refactoring. So here to refactor your component to a testable component you should pass factory to your class's constructor as a parameter.

And what about localVariable:

It really depends on your situation and what you expect from your unit to do (here your unit is doSomething method). If it is a variable that you expext from your method to create as part of its task and it should be created based on some logic in method in each call, there is no problem let it be there, but if it provides some other logic to your method and can be passed as parameter to your class you can pass it as parameter to your class's cunstructor.

One more thing, be carefull when you are doing refactoring there will be many other components that use your component, you should do your refactoring step by step and you should not change the logic of your method.

答案2

得分: 0

另外加入另一个观点:如果面临必须测试一个给定类并且不被允许更改需要测试的类的情况,你可以选择使用像 PowerMock(https://github.com/powermock/powermock)这样的框架,它提供了增强的模拟能力。

但要注意,仅仅为了证明难以测试的代码而使用 PowerMock 是不可取的。Tashkhisi 的答案无疑是更好的通用方法。

英文:

To add another perspective: If faced with situations in which you have to test a given class and aren't permitted to change the class you need to test, you have the option to use a framework like PowerMock (https://github.com/powermock/powermock) that offers enhanced mocking capabilities.

But be aware that using PowerMock for the sole purpose of justifying hard to test code is not advisable. Tashkhisi's answer is by far the better general purpose approach.

huangapple
  • 本文由 发表于 2020年10月18日 00:22:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/64404657.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定