【问题标题】:Mocking a class with multiple mocked dependency as constructor模拟具有多个模拟依赖项的类作为构造函数
【发布时间】:2017-09-30 00:45:39
【问题描述】:

我一直在尝试模拟我的服务/业务类以开始测试我的应用程序,但其他类有许多“依赖项”,主要是存储库和传递给这些存储库的存根。 我一直在尝试设置它以便能够对我的服务进行单元测试,但我不断收到错误,我真的不知道我的设置是否正确:

我没有包含接口,因为我觉得没有必要,但如果需要,可以。

    public abstract class  DemoRepo<T> implements Repository<T> {

        private dbStub stub;
        private Class<T> clazz;


        public DemoRepo(DbStub stub,Class<T> clazz){
            this.clazz = clazz;
            this.stub = stub;
        }

        @Override
        public void add(T item) {
            stub.inSert(item);
        }
        @Override
        public void update(T item) {
            stub.update(item);
        }
        ...

    }

然后这 2 个存储库为每个类扩展抽象类

    public class Class1Repo extends DemoRepo<Class1> {
        public Class1Repo(DbStub stub) {
            super(stub,Class1.class);
        }
    }


    public class Class2Repo extends DemoRepo<Class2> {
        public Class2Repo(DbStub stub) {
            super(stub,Class2.class);
        }
    }

对于使用之前创建的 2 个存储库的抽象服务也是如此。

    public abstract class AbstractService implements ClassService {
        private Repository<Class1> class1Repository;
        private Repository<Class2> class2Repository;

        public AbstractService(Repository<Class1> class1Repository, Repository<Class2> class2Repository) {
            this.class1Repository = class1Repository;
            this.class2Repository = class2Repository;
        }

        public boolean itemValiation(String itemId){
            Class1 item = class1Repository.findOne(itemId);
            item.setValidated(true);
            class1Repository.update(item);
            return true;
        }

        .....

    }

最后这是我要测试的服务:

    public class DemoImplService extends AbstractService {

        public DemoImplService(Class1Repo c1repo,Class2Repo c2repo){
            super(c1repo, c2repo);
        }
    }

但正如您所见,我需要传递 2 个模拟存储库,它们自己是从模拟的“存根”实例化的,这是我的问题。

我尝试了很多不同的方法,但最近的一个给我带来了麻烦:

class DemoImplServiceTest {
    @Mock
    private DbStub stub;

    private DemoImplService service;

    @InjectMocks
    private Class1Repo repo;

    @InjectMocks
    private Class2Repo repor;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks( this );
        Class1Repo repo = new Class1Repo(stub);
        Class2Repo repor = new Class2Repo(stub);
        DemoImplService service = new DemoImplService(repo,repor);
    }

    @Test
    void itemValiation() {
        Class1 c1 = new Class1();
        **when (repo.findOne("1")).thenReturn(c1);**
        //java.lang.NullPointerException
    }

}

我的逻辑是尝试使用 mock / injectmocks 机制,然后只是模拟存储库,因为我真的不需要模拟 Stub 但它没有编译我得到java.lang.NullPointerException

我也尝试使用ReflectionTestUtils.setField 设置 2 存储库,但我什至没有以这种方式编译,所以我放弃了。


更新:

新课程

class DemoImplServiceTest {

@Mock
private Class1Repo repo;
@Mock
private Class2Repo repor;
@InjectMocks
private DemoImplService service;


@Before
public void setUp() {
    MockitoAnnotations.initMocks( this );
    Class1 object = new Class1();
    when (repo.findOne("1")).thenReturn(object);
}

@Test
void itemValiation() {
   boolean updated = service.itemValiation("1");
   assertTrue( updated );
   verify( repo ).findOne("1");
   ArgumentCaptor<Class1> class1Captor = ArgumentCaptor.forClass( Class1.class );
   verify( repo ).update( class1Captor.capture() );
   Class1 updatedCclass1 = class1Captor.getValue();
   assertTrue( Class1.isValidated() );
}

这行boolean updated = service.itemValiation("1"); 是失败的:java.lang.NullPointerException

我尝试过声明

    Class1 object = new Class1();
    when (repo.findOne("1")).thenReturn(object);

void itemValiation() func 中,但这并没有改变任何东西

最后一件事是,如果我在测试函数中添加方法service = new DemoImplService(repo,repor);,这次我会得到一个不同的空指针异常,它位于该行的 itemValidation 方法中的 AbstractService 中class1Repository.update(item);

更新 2

没有实例化类的完整异常:

    java.lang.NullPointerException
        at com.jd.mypackage.test.services.ImplServiceTest.itemValiation(ImplServiceTest.java:187)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:316)
        at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:114)
        at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.lambda$invokeTestMethod$6(MethodTestDescriptor.java:171)
        at org.junit.jupiter.engine.descriptor.MethodTestDescriptor$$Lambda$141/655381473.execute(Unknown Source)
        at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
        at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.invokeTestMethod(MethodTestDescriptor.java:168)
        at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.execute(MethodTestDescriptor.java:115)
        at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.execute(MethodTestDescriptor.java:57)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$1(HierarchicalTestExecutor.java:81)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$109/981661423.execute(Unknown Source)
        at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:76)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$1(HierarchicalTestExecutor.java:91)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$109/981661423.execute(Unknown Source)
        at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:76)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$1(HierarchicalTestExecutor.java:91)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$109/981661423.execute(Unknown Source)
        at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:76)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:51)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:87)
        at org.junit.platform.launcher.Launcher.execute(Launcher.java:93)
        at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:61)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

【问题讨论】:

  • 如果使用injectMocks,则无需创建对象。请在出现空指针异常的地方粘贴no行
  • when (repo.findOne("1")).thenReturn(c1);

标签: java unit-testing mocking mockito


【解决方案1】:

我认为您应该在要测试的类上使用 @InjectMocks 并在该类的依赖项上使用 @Mock。

class DemoImplServiceTest {
    @InjectMocks
    private DemoImplService service;

    @Mock
    private Class1Repo repo;

    @Mock
    private Class2Repo repor;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testMethod() {
        ...
        ...
    }

}

【讨论】:

  • 是的,但是模拟 DbStub 来实例化 class1 存储库呢?没有必要吗? @Mock private DbStub stub; @InjectMocks private Class1Repo repo; @InjectMocks private Class2Repo repor; private =&gt; @InjectInjectedMocks DemoImplService service;
  • 你不需要那个,因为你正在创建模拟,它们只是模拟真实对象的行为。
  • 您是否仍然收到异常?只是问,因为您在上次发表评论后接受了答案
  • 实际上我仍然得到它刚刚移动的异常。现在 when(repo.findOne("1")).thenReturn(c1);作品。但是DemoImplService. itemValiation() 没有:(....
  • 您能展示一下您的 itemValiation 测试方法现在的样子吗?或者你可以更新整个测试类,这样我就可以看到你实际改变了什么。
猜你喜欢
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多