Java 为工厂类创建的对象注入 Mocks
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21879804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Inject Mocks for objects created by Factory classes
提问by saravana_pc
I have the following class:
我有以下课程:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
And the Test class:
和测试类:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
}
How could I inject an Apple instance as a mock in MyClass?
如何在 MyClass 中注入一个 Apple 实例作为模拟?
采纳答案by Avi
You have 3 possibilities to solve this:
您有 3 种可能性来解决这个问题:
Abstract factory: Instead of using a static method, use a concrete factory class:
抽象工厂:不使用静态方法,而是使用具体工厂类:
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
In your test class, mock the factory:
在您的测试类中,模拟工厂:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private AppleFactory appleFactoryMock;
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}
PowerMock: Use PowerMock to create a mock of a static method. Look at my answer to a relevant questionto see how it's done.
PowerMock:使用 PowerMock 创建静态方法的模拟。查看我对相关问题的回答,了解它是如何完成的。
Testable class: Make the Apple
creation wrapped in a protected
method and create a test class that overrides it:
可测试类:将Apple
创建包装在一个protected
方法中并创建一个覆盖它的测试类:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
@Override
public void createApple() {
return appleMock;
}
}
}
Of course, in your test class you should test TestableMyClass
and not MyClass
.
当然,在你的测试类中你应该测试TestableMyClass
而不是MyClass
.
I'll tell you my opinion on each of the methods:
我会告诉你我对每种方法的看法:
The abstract factory method is the best one- This is a clear design that hides the implementation details
The testable class - Is the second option which requires minimum changes
- The
PowerMock
option is my least favorite - Instead of going for a better design, you ignore and hide your problem. But that's still a valid option.
抽象工厂方法是最好的- 这是一个隐藏实现细节的清晰设计
可测试类 - 是需要最少更改的第二个选项
- 这个
PowerMock
选项是我最不喜欢的——你没有去寻求更好的设计,而是忽略并隐藏你的问题。但这仍然是一个有效的选择。
回答by Glauco Cucchiar
In addition of the solution proposed by Avi, you can choose a fourth possibility:
除了 Avi 提出的解决方案,您还可以选择第四种可能性:
Inject into Factory: This is, for me, the best option when you already have code to refacrot. With this solution you don't have to change porduction code but only factory class and test.
注入工厂:对我来说,这是当您已经有代码可以重构时的最佳选择。使用此解决方案,您不必更改生产代码,而只需更改工厂类和测试。
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = apple;
}
}
Now you can use your static factory simply:
现在你可以简单地使用你的静态工厂:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}
回答by ugurkocak1980
Regarding the first answer of Avi & Ev0oD. Abstract classes can only be extended and not implemented.
关于 Avi & Ev0oD 的第一个答案。抽象类只能扩展而不能实现。
public abstract class AppleFactory {
public abstract Apple createInstance(final String str);
}
public class AppleFactoryImpl extends AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}