深度模拟与Mockito和Spring Boot

huangapple go评论89阅读模式
英文:

Deep mocking with Mockito and Spring Boot

问题

我需要使用Mockito模拟“B”类使用的“A”类,然而我的测试用例是针对“D”类完成的。

看看我的示例:

  1. @Service
  2. public class Aclass {
  3. public Long sumTwoNumbers(Long a, Long b){
  4. return a + b;
  5. }
  6. }
  7. @Service
  8. public class Bclass {
  9. @Autowired
  10. private Aclass classA;
  11. public Long sunThreeNumbers(Long a, Long b, Long c){
  12. return classA.sumTwoNumbers(a, b) + c;
  13. }
  14. }
  15. @Service
  16. public class Cclass {
  17. @Autowired
  18. private Bclass classB;
  19. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  20. return classB.sunThreeNumbers(a, b, c) + d;
  21. }
  22. }
  23. @Service
  24. public class Dclass {
  25. @Autowired
  26. private Cclass classC;
  27. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  28. return classC.sunFourNumbers(a, b, c, d);
  29. }
  30. }

我的测试是:

  1. @ExtendWith(MockitoExtension.class)
  2. public class DclassTest{
  3. @InjectMocks
  4. private Dclass classD;
  5. @Mock
  6. private Aclass classA;
  7. /* 看,我需要模拟Aclass,而不是Bclass或Cclass。 */
  8. @Test
  9. public void testSunFourNumbers(){
  10. Mockito.when(classA.sumTwoNumbers(any(Long.class), any(Long.class))).thenReturn(0L);
  11. Long sum = classC.sunFourNumbers(1L, 1L, 1L, 1L);
  12. Assert.assertEquals(2L, sum);
  13. }
  14. }

这只是我需要的简单示例。

当我运行这个测试时,我收到了Dclass中的NullPointerException。

这是可能的吗?

英文:

I need to mock (with Mockito) the "A" class used by "B" class however my test case is done to "D" class.

See my example:

  1. @Service
  2. public class Aclass {
  3. public Long sumTwoNumbers(Long a, Long b){
  4. return a + b;
  5. }
  6. }
  7. @Service
  8. public class Bclass {
  9. @Autowired
  10. private Aclass classA;
  11. public Long sunThreeNumbers(Long a, Long b, Long c){
  12. return classA.sumTwoNumbers(a, b) + c;
  13. }
  14. }
  15. @Service
  16. public class Cclass {
  17. @Autowired
  18. private Bclass classB;
  19. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  20. return classB.sunThreeNumbers(a, b, c) + d;
  21. }
  22. }
  23. @Service
  24. public class Dclass {
  25. @Autowired
  26. private Cclass classC;
  27. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  28. return classC.sunFourNumbers(a, b, c, d);
  29. }
  30. }

My test is :

  1. @ExtendWith(MockitoExtension.class)
  2. public class DclassTest{
  3. @InjectMocks
  4. private Dclass classD;
  5. @Mock
  6. private Aclass classA;
  7. /* Look , I need to mock Aclass , not Bclass or Cclass. */
  8. @Test
  9. public void testSunFourNumbers(){
  10. Mockito.when(classA.sumTwoNumbers(any(Long.class), any(Long.class))).thenReturn(0L);
  11. Long sum = classC.sunFourNumbers(1L, 1L, 1L, 1L);
  12. Assert.assertEquals(2L, sum);
  13. }
  14. }

It was a simple example of what I need.

When I run this I received NullPointerException in Dclass.

Is it possible ?

答案1

得分: 1

  1. 我认为你应该使用Mockito这样来测试你的Bclass
  2. public class BclassTest {
  3. Long a = 0L;
  4. Long b = 0L;
  5. Long c = 1L;
  6. @InjectMocks
  7. private Bclass bclass;
  8. @Mock
  9. private Aclass aclass;
  10. // 你应该在@Before方法中初始化你的Mock对象。
  11. @Before
  12. public void setup() {
  13. MockitoAnnotations.initMocks(this);
  14. }
  15. @Test
  16. public void testSunThreeNumbers() {
  17. Mockito.when(aclass.sumTwoNumbers(anyLong(), anyLong())).thenReturn(0L);
  18. assertEquals(Long.valueOf(1), bclass.sunThreeNumbers(a, b, c));
  19. }
  20. }
英文:

I Think You should Test Your class Bclass with Mockito Like this :

  1. public class BclassTest {
  2. Long a = 0L;
  3. Long b = 0L;
  4. Long c = 1L;
  5. @InjectMocks
  6. private Bclass bclass;
  7. @Mock
  8. private Aclass aclass;
  9. //You Should initialize your Mock Objects in @Before method.
  10. @Before
  11. public void setup() {
  12. MockitoAnnotations.initMocks(this);
  13. @Test
  14. public void testSunThreeNumbers(){
  15. Mockito.when(aclass.sumTwoNumbers(anyLong(),anyLong())).thenReturn(0L);
  16. assertEquals(Long.valueOf(1), bclass.sunThreeNumbers(Long a, Long b, Long c));
  17. }
  18. }
  19. }

答案2

得分: 1

根据示例代码,很明显以下服务的依赖关系如下:

  1. Dclass 依赖于 Cclass
  2. Cclass 依赖于 Bclass
  3. Bclass 依赖于 Aclass

当我们为 Dclass 编写单元测试案例(代码如下):

  1. @Service
  2. public class Dclass {
  3. @Autowired
  4. private Cclass classC;
  5. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  6. return classC.sunFourNumbers(a, b, c, d);
  7. }
  8. }

在这里,Dclass 直接依赖于 Cclass,因此在这种情况下,只需要模拟 Cclass。单元测试的目标是通过模拟其直接依赖项来测试小单元。

  1. @InjectMocks Dclass classD; // 现在它有所有三个模拟对象(但不需要 A 和 B 的模拟)
  2. @Mock Aclass classA; // 不需要(Dclass 不依赖于 Aclass)
  3. @Mock Bclass classB; // 不需要(Dclass 不依赖于 Bclass)
  4. @Mock Cclass classC; // **必需** - 因为 Dclass 直接依赖于 Cclass
  5. 根据您的代码 - 您为 Aclass 创建了一个模拟对象并将其注入到了 Dclass
  6. Aclass 模拟对象编写了 When(...).then(...)
  7. @Test
  8. public void testSunFourNumbers(){
  9. Mockito.when(classA.sumTwoNumbers(any(Long.class), any(Long.class))).thenReturn(0L);
  10. // 由于您的代码中没有针对 'classC' 的模拟对象,它将为 null,导致空指针异常
  11. Long sum = classC.sunFourNumbers(1L, 1L, 1L, 1L);
  12. Assert.assertEquals(2L, sum);
  13. }
英文:

As per the example code, its pretty clear that below services dependent as below

  1. DClass depends on Cclass
  2. Cclass on Bclass and
  3. Bclass on Aclass

When we write unit test cases for Dclass (code as below),

  1. @Service
  2. public class Dclass {
  3. @Autowired
  4. private Cclass classC;
  5. public Long sunFourNumbers(Long a, Long b, Long c, Long d){
  6. return classC.sunFourNumbers(a, b, c, d);
  7. }
  8. }

Here Dclass is directly dependent on Cclass, so mocking Cclass is enough in this case. Unit testing is all about testing a small unit by mocking its direct dependents.

  1. @InjectMocks Dclass classD; // It has all 3 mocks now (but A and B mocks not needed)
  2. @Mock Aclass classA; //not needed (Dclass not dependent on Aclass)
  3. @Mock Bclass classB; //not needed (Dclass not dependent on Bclass)
  4. @Mock Cclass classC; // **Mandatory** - Because Dclass is directly dependent on Cclass
  5. As per your code - you have a mock for Aclass and injected mock into Dclass.
  6. When(...).then(...) written for Aclass mock.
  7. @Test
  8. public void testSunFourNumbers(){
  9. Mockito.when(classA.sumTwoNumbers(any(Long.class), any(Long.class))).thenReturn(0L);
  10. //Since you don't have mock for 'classC' in your code, it will go as null and result in nullpointer
  11. Long sum = classC.sunFourNumbers(1L, 1L, 1L, 1L);
  12. Assert.assertEquals(2L, sum);
  13. }

huangapple
  • 本文由 发表于 2020年8月15日 06:26:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63420728.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定