【问题标题】:Mockito inject nested beanMockito 注入嵌套 bean
【发布时间】:2016-05-25 15:00:40
【问题描述】:

我对 mockito 并不陌生,但这次我在工作中发现了一个有趣的案例。我希望你能帮我解决这个问题。

我需要注入 mock 以在测试期间更改某些方法行为。问题是,bean 结构是嵌套的,并且这个 bean 在其他 bean 中,无法从测试方法访问。我的代码如下所示:

@Component
class TestedService { 
  @Autowired
  NestedService nestedService;
}

@Component
class NestedService {
  @Autowired
  MoreNestedService moreNestedService;
}

@Component
class MoreNestedService {
  @Autowired
  NestedDao nestedDao;
}

@Component
class NestedDao {
  public int method(){
    //typical dao method, details omitted
  };
}

所以在我的测试中,我希望调用 NestedDao.method 返回模拟答案。

class Test { 
  @Mock
  NestedDao nestedDao;

  @InjectMocks
  TestedService testedSevice;

  @Test
  void test() {
    Mockito.when(nestedDao.method()).thenReturn(1);
    //data preparation omitted
    testedSevice.callNestedServiceThatCallsNestedDaoMethod();
    //assertions omitted
  }
}

我已经尝试做一个 initMocks:

@BeforeMethod
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

还要在我的测试类上添加注释:

@RunWith(MockitoJUnitRunner.class)

总是从方法中得到空指针或错误答案(未模拟)。

我猜是这个嵌套调用错误,使得无法模拟这个 Dao。 我还读到@InjectMocks 仅适用于 setter 或构造函数注入,我缺少这些(只是私有字段上的 @Autowire),但当我尝试时它没有工作。

猜猜我错过了什么? ;)

【问题讨论】:

  • 你不是在模拟嵌套服务,那么它应该如何工作?并且通常不模拟nestedDao,而是调用when(nestedService.callDaoMethod()).return("stuff which the dao should return")
  • 好的,我怎样才能模拟嵌套服务,然后模拟嵌套在其中的东西,然后再次相同?在互联网上没有这样做的例子。我看到的另一种方法是使用构造函数并创建对象,但是依赖项对我来说太复杂了(我是项目中的新手)。如果我能告诉 NestedDao 类必须像往常一样返回另一个对象,那就太好了。这个调用在层次结构中很深,所以很难模拟所有嵌套的服务。
  • “然后模拟嵌套在其中的东西,然后再次相同” 没有理由这样做。这是一个单元测试。您正在测试 TestedService 而不是 NestedService 及其嵌套依赖项的实现细节。例如你的班级MoreNestedService ...这个班级甚至不需要在测试中提及。您只模拟 TestedService 并告诉该模拟在某个方法调用上返回什么。这个方法可能在“现实生活”中调用嵌套方法现在并不重要。
  • 顺便说一句:请创建一个minimal reproducible example。你的课程已经没问题了,但是在不知道你正在测试、测试数据是什么以及你断言什么的情况下,很难告诉你问题出在哪里。您仍然可以使用抽象数据和类名,但该示例应该重现您当前的问题。
  • 好的,等我有空的时候我会做的:)谢谢你到目前为止的帮助。

标签: java spring junit dependency-injection mockito


【解决方案1】:

您可以使用@MockBean 代替@Mock 和@InjectionMock。

@RunWith(SpringRunner.class)
@SpringBootTest
class Test { 
  @MockBean
  NestedDao nestedDao;

  @Autowired
  TestedService testedSevice;

  @Test
  void test() {
    Mockito.when(nestedDao.method()).thenReturn(1);
    //data preparation omitted
    testedSevice.callNestedServiceThatCallsNestedDaoMethod();
    //assertions omitted
  }
}

【讨论】:

  • 虽然质疑在“单元测试”中包含另一个 bean 的目的可能是有效的,但在某些情况下它可能适用,然后我会说这个答案是正确的。跨度>
【解决方案2】:

这对我来说是有道理的,你错了, 为什么? 这是因为您正在测试 TestedService 以及与 NestedService 的交互,而不是与 Dao,因此应该在 NestedService 测试中验证 Dao 交互

看这个:

@Component
class TestedService { 

  @Autowired
  NestedService nestedService;

  String sayHello(String name){
     String result = "hello" + nestedService.toUpperCase(name)
  }
}

@Component
class NestedService {

  @Autowired
  MoreNestedService moreNestedService;

  String toUpperCase(String name){
        String nameWithDotAtTheEnd = moreNestedService.atDot(name);
        return nameWithDotAtTheEnd.toUpperCase();

  }

}

在你的测试中:

class Test { 
  @Mock
  NestedService nestedService;

  @InjectMocks
  TestedService testedSevice;

  @Test
  void test() {
    Mockito.when(nestedService.toUpperCase("rene")).thenReturn("RENE.");
    //data preparation omitted
    Assert.assertEquals("hello RENE.", testedSevice.sayHello("rene"));
    //assertions omitted
  }
}

如您所见,您假设 TestedService 的依赖项运行良好,您只需要验证 hello 是否被添加为字符串的前缀,

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    相关资源
    最近更新 更多