调用模仿方法时,春季模仿测试失败

时间:2019-03-21 04:04:51

标签: spring spring-boot mockito junit4

这里有两个Spring Service;

public interface Service01 {
     String test01(String name);
}

@Service 
public class Service01Impl implements Service01 { 

     @Override
     public String test01(String name) {
          if (!"123".equals(name)) {
              throw new RuntimeException("name is illegal");
          }
          return name;
     }
}

@Service 
public class Service02 { 
     @Autowired
     private Service01 service01;
     @Autowired
     private Service03 service03;

     public String test02(String name) {
          service03.checkNameNotNull(name);
          return service01.test01(name);
     }
}

@Service 
public class Service03 { 
     public void checkNameNotNull(String name) {
          if (name == null) {
              throw new RuntimeException("name is null");
          }
     }
}

然后这是我的testClass:

public class TestCalss {
    @Mock
    private Service01 service01;
    @Autowired
    private Service02 service02;

    @Test
    public void testMock() {
        // mock service
        when(service01.name("abc")).thenReturn("mock return abc");

        // here will be success
        String nameAbc = service01.test01("abc")
        Assert.assertEquals("mock return abc", nameAbc);

        // but here got exception: `name is illegal`
        String name = service02.test02("abc");
        Assert.assertEquals("mock return abc", name);
    }

}

第一季度: 为什么在第String name = service02.test02("abc");

行出现异常
java.lang.RuntimeException: name is illegal

第二季度:当我打电话给Service01时,如何嘲笑Service02

-编辑

第二季度固定为@InjectMocks

Q3: 如何仅模拟Service01,而不模拟Service03

我要使此检查没有模拟 service03.checkNameNotNull(name);

1 个答案:

答案 0 :(得分:1)

设置模拟程序时,需要使用ArgumentMatcher-而不是传入字符串文字"abc",而需要使行看起来像when(service01.name(eq("abc"))).thenReturn...

如果您不介意传入的实际字符串是什么,那么还有其他匹配器也可以使用,例如anyString()

您也不想在测试中使用@Autowired-如果您希望被测类自动向其注入模拟,那么您需要实例化该模拟并将其注入,而不是真正的Spring。豆。

最直接的方法是使用MockitoJUnitRunner@InjectMocks批注:

@RunWith(MockitoJUnitRunner.class)
public class TestCalss {
    @Mock
    private Service01 service01;
    @InjectMocks
    private Service02 service02;

...

要注入非模拟类,您需要使用@Before批注,并通过某种方式将对象传递到类中(就像在普通Java代码中一样)。

我的首选方法是拥有一个构造函数,该构造函数将依赖项设置为类上的私有最终字段,但是Spring还提供了一个类ReflectionTestUtils,如果您确实想使用私有字段,可以使用该类没有二传手。

是这样的:

@Service 
public class Service02 { 

     private final Service01 service01;
     private final Service03 service03;

     @Autowired
     public Service02 (Service01 service01, Service03 service03) {
         this.service01 = service01;
         this.service03 = service03;
     }

    ...
}

@RunWith(MockitoJUnitRunner.class)
public class TestClass {

    @Mock
    private Service01 service01;

    private Service02 underTest;

    @Before
    public void setup() {
        this.underTest = new Service02(this.service01, new Service03());
    }
    ...
}

如果您想在其他情况下要模拟的对象上调用真实方法,则可能表明您的类做了太多的事情,实际上应该是两个或更多个较小的类,但这也是可能的:{ {1}}