Java 使用Mockito通过一系列依赖类注入mock
嗨,我已经实现了一系列类,它们使用dagger 2注入为每个类注入依赖项,我试图模拟这些类来运行我的单元测试,但它无法初始化从具有依赖项的较低层类中找到的依赖项 这在真实环境中运行良好,但不适用于测试 我尝试将所有依赖项标记为Spy或Mock,但它似乎只在调用的类的第一层上注入Mock。下面是标记为example1、Two、three的三个类,后面是测试类 ExampleOne有一个方法调用Example2中的另一个方法,然后最终调用ExampleThree中的另一个方法Java 使用Mockito通过一系列依赖类注入mock,java,unit-testing,dependency-injection,mockito,Java,Unit Testing,Dependency Injection,Mockito,嗨,我已经实现了一系列类,它们使用dagger 2注入为每个类注入依赖项,我试图模拟这些类来运行我的单元测试,但它无法初始化从具有依赖项的较低层类中找到的依赖项 这在真实环境中运行良好,但不适用于测试 我尝试将所有依赖项标记为Spy或Mock,但它似乎只在调用的类的第一层上注入Mock。下面是标记为example1、Two、three的三个类,后面是测试类 ExampleOne有一个方法调用Example2中的另一个方法,然后最终调用ExampleThree中的另一个方法 public clas
public class ExampleOne{
@Inject
ExampleTwo exampleTwo;
//implementations below
public void doSomethingOne(){
exampleTwo.doSomethingTwo;
}
}
public class ExampleTwo{
@Inject
ExampleThree exampleThree
public void doSomethingTwo(){
exampleThree.doPrintHello();
}
}
public class ExampleThree{
public void doPrintHello(){
Log.d("Print","Hello")
}
}
只有示例二可以很好地注入模拟/间谍,而不是示例三
public class ExampleOne{
@Inject
ExampleTwo exampleTwo;
//implementations below
public void doSomethingOne(){
exampleTwo.doSomethingTwo;
}
}
public class ExampleTwo{
@Inject
ExampleThree exampleThree
public void doSomethingTwo(){
exampleThree.doPrintHello();
}
}
public class ExampleThree{
public void doPrintHello(){
Log.d("Print","Hello")
}
}
下面是我的测试
@RunWith(MockitoJUnitRunner.class)
public class TestExamples(){
@InjectMocks
ExampleOne exampleOne
@Spy
ExampleTwo exampleTwo = new ExampleTwo();
@Spy
ExampleThree exampleThree = new ExampleThree();
@Test
void test(){
exampleOne.doSomethingOne();
//some testing code here
}
}
通过构造函数注入或方法注入实践显式依赖性原则。接下来,应该隔离单元测试。在这种情况下,您不需要访问实现问题。您的类与实现问题紧密耦合,而不是抽象(这是一种代码味道)
public class ExampleOne {
ExampleTwo exampleTwo;
@Inject
public ExampleOne(ExampleTwo exampleTwo) {
this.exampleTwo = exampleTwo;
}
//implementations below
public void doSomethingOne(){
exampleTwo.doSomethingTwo();
}
}
public interface ExampleTwo {
void doSomethingTwo();
}
public class ConcreteExampleTwo implements ExampleTwo {
private ExampleThree exampleThree;
@Inject
public ConcreteExampleTwo(ExampleThree exampleThree) {
this.exampleThree = exampleThree;
}
public void doSomethingTwo(){
exampleThree.doPrintHello();
}
}
public interface ExampleThree {
void doPrintHello();
}
//...code removed for brevity
ExampleOne
在该级别上有一个依赖项,如果该依赖项不能在没有副作用的情况下被模拟/存根/伪造,则目标类的设计存在问题
@RunWith(MockitoJUnitRunner.class)
public class TestExamples(){
@Mock
ExampleTwo exampleTwo;
@InjectMocks
ExampleOne exampleOne
@Test
void test(){
exampleOne.doSomethingOne();
verify(exampleTwo).doSomethingTwo();
}
}
通过以上建议的更改,ExampleOne
可以单独测试,而不会产生任何连锁反应
ExampleTwo
的具体实现也可以单独进行测试。这只是我的观点,但您应该通过构造函数或方法来实践显式依赖原则。接下来,应该隔离单元测试。在这种情况下,您不需要访问实现问题。您的类与实现问题紧密耦合,而不是抽象,这是一种代码味道。ExampleOne
有一个依赖项,如果该依赖项不能被模仿/存根/伪造而没有副作用,那么目标类的设计就有问题。那么设计有缺陷吗?这是使用delegator模式,这是一种常见的设计模式。尽管如此,在其他情况下,您仍需要调用两个或三个需要创建依赖项的类。此解决方案在生产中工作得非常好,只是因为它在生产中工作并不使其成为最佳解决方案,或者设计没有缺陷。你只会招致技术债务。在指出一个依赖关系时,我指的是同一级别的依赖关系。在完整的生产代码中,对于每个类,我都有一个空构造函数,上面标记了注入,以自动连接它并在生产中工作。我是否应该删除@InjectExampleTower并将其添加到ExampleOne的构造函数中,就像对任何正在进行的类一样?@jonney注意到我的示例中的构造函数不是空的。还有,我的课程依赖于抽象,而不是具体化。@jonney我还建议你阅读坚实的原则。好的,谢谢,让我试一试。我认为这里的主要修复方法是使用ExampleTree作为构造函数的参数,我还将阅读坚实的原则OK it fixed my issue。谢谢我只是想知道这个方法。假设ExampleOne有多个依赖项。将所有这些依赖项添加到构造函数中而不是我们执行Inject-example2-Inject-exampletree-Inject-exampletree-Inject-exampletree而不是Inject/constructor(example2,Three,Four…)会看起来“丑陋”吗?