【问题标题】:Mockito Mock and Spy in SpringBoot AppSpring Boot 应用程序中的 Mockito 模拟和间谍
【发布时间】:2017-07-12 16:58:14
【问题描述】:

我已经阅读了很多文章/博客/StackOverflow 问题,但关于 Mockito 模拟和间谍的困惑仍然存在。所以,我开始尝试在一个小的Spring Boot 应用程序中实现它们。我的应用程序有一个 ProductRepository 扩展 CrudRepository

目前我正在通过模拟ProductRepository 来测试存储库,如下所示

  @RunWith(SpringRunner.class)
  @SpringBootTest(classes = {RepositoryConfiguration.class})
  public class ProductRepositoryMockTest {

    @Mock
    private ProductRepository productRepository;
    @Mock
    private Product product;

    @Test
    public void testMockCreation(){
      assertNotNull(product);
      assertNotNull(productRepository);
    }

    @Test
    public void testSaveProduct() {
      assertThat(product.getId(), is(equalTo(0)));
      when(productRepository.save(product)).thenReturn(product);
      productRepository.save(product);
      //Obviously this will fail as product is not saved to db and hence   
      //@GeneratedValue won't come to play
      //assertThat(product.getId() , is(not(0)));
    }

     @Test
     public void testFindProductById() {

      when(productRepository.findOne(product.getId())).thenReturn(product);
      assertNotNull(productRepository.findOne(product.getId()));
      assertEquals(product, productRepository.findOne(product.getId()));
     }
   }

测试通过。这是正确的方法吗?我也想了解如何在这里使用@Spy 以及为什么需要它?任何与此相关的特定场景都非常受欢迎。

提前致谢。

【问题讨论】:

  • 不要对你的存储库进行单元测试。关注单元测试的服务层。如果您的存储库中有一些逻辑,那么这可能是一个设计缺陷。
  • 是的,明白了。谢谢。
  • @Maciej Kowalski 最后设法根据您的输入使用模拟和间谍来测试服务层。但不知道我是否做得正确,我的仓库位于github.com/ximanta/mockito_spy_example 您的观察将很有价值。如果需要,可以将其作为问题发布。谢谢。
  • 我检查了 repo.. 看看我的答案

标签: java unit-testing spring-boot junit mockito


【解决方案1】:

我查看了您的测试,有几件事要记住(这是基于我的经验,所以最终决定权取决于您):

1) Hamcrest - 如果可能的话,我强烈建议您将 Hamcrest 用于您的断言实现。 首先,它比标准的 junit 断言更加通用和功能丰富。 其次,您可能有一天需要(就像我在我的一个项目中所做的那样)例如从 junit 切换到 testng。 让所有断言都基于 xunit 中立的实现,切换不会那么痛苦。

2) 断言 - 代替 assertNullassertEquals 去 hamcrest 的 assertThat(String description, T value, Mathcer<T> matcher); 多亏了这一点,您将在测试中断时收到清晰的错误消息。

3) 小测试 - 在您的存储库测试中......不要将所有案例放在一个测试中。 尝试为以下情况创建许多小而简单的测试:findOne..count..findAll 等。 同样,当像这样的小测试中断时,会更容易找到问题。 如果有更多的案例出现,您最终不会得到 200 多行的测试用例,这是不可接受的

4) 命名 - 不要将您的测试命名为..testXYZ。 很明显,这些都是测试方法。 我建议使用 BDD 命名方式:shouldX_whenY_givenZ。 F.e. shouldReturnZeroCount_givenNoEntitiesInTheDatabase

5) 结构 - 尝试将每个测试实现分成三个明确的部分,包括 cmets 以获得最佳结果:

public void should..() throws Exception{
         // Arrange

            // when().then()
            // mock()

         // Act

            // classUnderTest.process()

         // Assert

           // assertThat(..)
   }

6) 不要在模拟/间谍测试之间拆分您的测试类。有一个 ImplTest。

7) 切勿模拟您正在测试的课程。在最坏的情况下,如果您必须模拟被测类的某些方法,请使用 Spy。 模拟的重点是隔离被测类中的实现,以便在测试期间只调用类逻辑。 仅模拟类的依赖项。

【讨论】:

  • 与使用构造函数/setter 方法使用模拟初始化被测对象相比,为什么不鼓励使用 InjectMock 注释?
猜你喜欢
  • 2016-10-06
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多