【问题标题】:testing Spring Retry throws an error: wanted * times, but was 1 time测试 Spring Retry 会抛出错误:想要 * 次,但是是 1 次
【发布时间】:2018-09-10 16:48:20
【问题描述】:

我使用 spring retry 并想对其进行单元测试。 但无法让单元测试工作。 请参阅下面的我的代码和测试。
当我运行测试时,它说应该是3 times,但实际上是1 time。 我一定想念什么。谢谢

 @RunWith(SpringJUnit4ClassRunner.class)
 public class MyOperationsTest
 private MyOperations myOperations;
 @mock 
 Param1 param1;
 @mock 
 Param2 param2AnotherOperation; 

 @Before 
 public void setUp(){
     myOperations = new MyOperations(param1, param2AnotherOperation);     
 }
 @Test
    public void testmyMethodWithFailure_ShouldRetry3TimesThenThrowException() {
        MyException exception1 = new MyException ("exception 1");
        MyException exception2 = new MyException ("exception 2");
        MyException exception3 = new MyException ("exception 3");

        Mockito.doThrow(exception1).when(param2AnotherOperation).itsMethod(firstParam, secondParam);
        Mockito.doThrow(exception2).when(param2AnotherOperation).itsMethod(firstParam, secondParam);
        Mockito.doThrow(exception3).when(param2AnotherOperation).itsMethod(firstParam, secondParam);

        Throwable writingException =
                catchThrowable(() -> myOperations.myMethod(firstParam, secondParam));

        Mockito.verify(param2AnotherOperation, times(3)).itsMethod(firstParam, secondParam);
    }

在 MyOperations 类中

@Service
@EnableRetry
    public class MyOperations{
    Param1 param1;
    Param2AnotherOperation param2AnotherOperation
    public MyOperations(Param1 param1, Param2AnotherOperation param2AnotherOperation) {
        this.param1 = param1;
        this.param2AnotherOperation = param2AnotherOperation;

}

    @Retryable(value = {MyExceptoin.class},
            maxAttemptsExpression = "3",
            backoff = @Backoff(delayExpression = "#{@retryInterval}"))
            public void myMethod(firstParam, secondParam){
            try {                  
                param2AnotherOperation.itsMethod(firstParam, secondParam);
                ...                    
            }
            catch(Exception ex){
                throw new MyExceptoin(ex);
            }
        }

    }

【问题讨论】:

  • 您的代码有很多编译错误,请全部修复。

标签: java unit-testing spring-retry


【解决方案1】:

@EnableRetry 必须在 @Configuration 类上;你把它放在@Service bean 上。

编辑

这里有一个快速入门的技巧;我还没有测试它,但它应该很接近......

@RunWith(SpringRunner.class)
public class So52262230ApplicationTests {

    private MyOperations myOperations;

    @Autowired
    Param1 param1;

    @Autowired
    Param2 param2AnotherOperation;

    @Autowired
    MyOperations myoperations;

    @Test
    public void testmyMethodWithFailure_ShouldRetry3TimesThenThrowException() {
        MyException exception1 = new MyException("exception 1");
        MyException exception2 = new MyException("exception 2");
        MyException exception3 = new MyException("exception 3");

        Mockito.doThrow(exception1).when(param2AnotherOperation).itsMethod(firstParam, secondParam);
        Mockito.doThrow(exception2).when(param2AnotherOperation).itsMethod(firstParam, secondParam);
        Mockito.doThrow(exception3).when(param2AnotherOperation).itsMethod(firstParam, secondParam);

        Throwable writingException = catchThrowable(() -> myOperations.myMethod(firstParam, secondParam));

        Mockito.verify(param2AnotherOperation, times(3)).itsMethod(firstParam, secondParam);
    }

    @Configuration
    @EnableRetry
    public static class Config {

        @Bean
        public Param1 param1() {
            //return a mock
        }

        @Bean
        public Param2 param2() {
            //return a mock
        }

        @Bean
        public MyOperations myOperations() {
            return new MyOperations(param1(), param2());
        }
    }

}

【讨论】:

  • 嗯,但是当我从集成测试它时,它工作正常。我确实看到方法被调用了 3 次。
  • 这是因为您正在创建实例,而不是 Spring。 myOperations = new MyOperations(param1, param2AnotherOperation); 需要是测试应用上下文中的Spring Bean。
  • 谢谢。如何在我的测试中创建一个 spring bean?对不起,春天的新人。告诉我,或者我可以谷歌它。
  • 好的,如果我使用 SpringBootTest 创建一个 MyOperations 的 bean,我怎样才能让 myMothod 在不模拟的情况下抛出 MyException?
【解决方案2】:

正如所指出的,为了让您的重试工作,您需要 Spring 来帮助您,这意味着您应该从 Spring 上下文中选择您的 bean;所以你必须删除 MyOperations 类的显式实例化。此外,您对 MyOperations 类的依赖项需要插入到 SpringContext 中(以便它们可以在上下文本身中绑定在一起),这可以通过使用 @MockBean 注释您的模拟 bean 来完成。这将用这些模拟 bean 替换 SpringContext 中的实际 bean。有了所有这些,您将能够在测试中利用 Spring 的功能,例如 @Retryable

所以,类似:

@RunWith(SpringRunner.class)
 public class MyOperationsTest

 @MockBean // pushed 1st mocked dependency to Spring context
 Param1 param1;

 @MockBean // pushed 2nd mocked dependency to Spring context
 Param2 param2AnotherOperation; 

 @Autowired //Getting the hydrated bean for class under test from context
 private MyOperations myOperations;

 @Before 
 public void setUp(){
 // No manual instantiation required; picking bean from context
 //    myOperations = new MyOperations(param1, param2AnotherOperation);     
...
 }

... continue with tests ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多