可重试注释-Junit5 -Mockito-是否可能

发布于 2025-01-20 19:57:48 字数 440 浏览 3 评论 0原文

是否可以使用Junit 5 Mockito编写单元测试进行重试注释?

我的服务接口只有一种方法,该方法从远程URL下载文件

@service
interface downloadpdf{
@Retryable(value = { FileNotFoundException.class, HttpClientErrorException.class }, maxAttempts = 5, backoff = @Backoff(delay = 1000))
public string downloadpdffile(string remoteurl, string pdfname);    
}

,我尝试引用站点并使用Spring4JunitRunner实现进行测试重试。与实施混淆了。是否可以使用Junit 5 Mockito编写单元测试进行重试注释?您能在这里详细说明解决方案吗?

Is it possible to write unit test using Junit 5 mockito for retryable annotations?

I am having a service interface which has only one method, which downloads the file from remote url

@service
interface downloadpdf{
@Retryable(value = { FileNotFoundException.class, HttpClientErrorException.class }, maxAttempts = 5, backoff = @Backoff(delay = 1000))
public string downloadpdffile(string remoteurl, string pdfname);    
}

I have tried referring sites and found using Spring4JunitRunner implementation to test retry. Got confused with implementation. Is it possible to write unit test using Junit 5 mockito for retryable annotations?. Could you please elaborate on the solution here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

泅人 2025-01-27 19:57:48

您需要使用@SpringJunitConfig(这等同于Junit4 Runner)。或@springboottest在使用启动时。

@retryable仅与Spring管理的Bean一起使用 - 它将Bean包裹在代理中。

@SpringBootApplication
@EnableRetry
public class So71849077Application {

    public static void main(String[] args) {
        SpringApplication.run(So71849077Application.class, args);
    }

}

@Component
class RetryableClass {

    private SomeService service;

    void setService(SomeService service) {
        this.service = service;
    }

    @Retryable
    void retryableMethod(String in) {
        service.callme();
        throw new RuntimeException();
    }

    @Recover
    void recover(Exception ex, String  in) {
        service.failed();
    }

}

interface SomeService {

    void callme();

    void failed();

}
@SpringBootTest
class So71849077ApplicationTests {

    @MockBean
    SomeService service;

    @Test
    void testRetry(@Autowired RetryableClass retryable) {
        SomeService service = mock(SomeService.class);
        retryable.setService(service);

        retryable.retryableMethod("foo");
        verify(service, times(3)).callme();
        verify(service).failed();
    }

}

You need to use @SpringJUnitConfig (which is the equivalent of the JUnit4 runner). Or @SpringBootTest as you are using Boot.

@Retryable only works with beans managed by Spring - it wraps the bean in a proxy.

@SpringBootApplication
@EnableRetry
public class So71849077Application {

    public static void main(String[] args) {
        SpringApplication.run(So71849077Application.class, args);
    }

}

@Component
class RetryableClass {

    private SomeService service;

    void setService(SomeService service) {
        this.service = service;
    }

    @Retryable
    void retryableMethod(String in) {
        service.callme();
        throw new RuntimeException();
    }

    @Recover
    void recover(Exception ex, String  in) {
        service.failed();
    }

}

interface SomeService {

    void callme();

    void failed();

}
@SpringBootTest
class So71849077ApplicationTests {

    @MockBean
    SomeService service;

    @Test
    void testRetry(@Autowired RetryableClass retryable) {
        SomeService service = mock(SomeService.class);
        retryable.setService(service);

        retryable.retryableMethod("foo");
        verify(service, times(3)).callme();
        verify(service).failed();
    }

}
老娘不死你永远是小三 2025-01-27 19:57:48

我也尝试使用 Junit5 来实现这一点。

尝试了各种选择,但这没有帮助。然后在谷歌搜索几个小时后,得到以下链接,这有助于成功。

https:// /doctorjw.wordpress.com/2022/04/29/spring-testing-a-single-bean-in-junit-5-springextension/

参考代码下面,详细解释请参考博客。

@Component
public class MyClass {
private ObjectMapper objectMapper;

private RestTemplate restTemplate;

@Value("${testValue:5}")
private int value;


@Retryable(....)
public void doStuff() throws SomeException {
...
}
}

我发现,如果我这样声明我的测试类:

@ExtendWith( SpringExtension.class )
@Import( { MyClass.class, ObjectMapper.class } )
@EnableRetry
public class MyClassTest {

@Autowired
private MyClass myClass;

@MockBean
private RestTemplate restTemplate;

@Autowired
private ObjectMapper objectMapper;

@BeforeEach
public void setup() {
    // If we are going to jack with the object configuration,
    // we need to do so on the actual object, not the Spring proxy.
    // So, use AopTestUtils to get around the proxy to the actual obj.

    TestingUtils.setFieldValue( AopTestUtils.getTargetObject( myClass ), "value", 10 );
}

}

您会注意到包含另外 1 个类,TestingUtils.class。这个类看起来像:

public class TestingUtils {

public static void setFieldValue( Object object, String fieldName, Object value ) {
    Field field = ReflectionUtils.findField( object.getClass(), fieldName );
    ReflectionUtils.makeAccessible( field );

    ReflectionUtils.setField( field, object, value );
}
}

所有学分都归博客作者所有。

I was also trying to implement this using Junit5.

Tried various options but that didn't help. Then after googling for few hours, got the following link and it helped to succeed.

https://doctorjw.wordpress.com/2022/04/29/spring-testing-a-single-bean-in-junit-5-springextension/

Reference code below, for detailed explanation, please refer the blog.

@Component
public class MyClass {
private ObjectMapper objectMapper;

private RestTemplate restTemplate;

@Value("${testValue:5}")
private int value;


@Retryable(....)
public void doStuff() throws SomeException {
...
}
}

What I’ve discovered is, if I declare my test class this way:

@ExtendWith( SpringExtension.class )
@Import( { MyClass.class, ObjectMapper.class } )
@EnableRetry
public class MyClassTest {

@Autowired
private MyClass myClass;

@MockBean
private RestTemplate restTemplate;

@Autowired
private ObjectMapper objectMapper;

@BeforeEach
public void setup() {
    // If we are going to jack with the object configuration,
    // we need to do so on the actual object, not the Spring proxy.
    // So, use AopTestUtils to get around the proxy to the actual obj.

    TestingUtils.setFieldValue( AopTestUtils.getTargetObject( myClass ), "value", 10 );
}

}

You will notice the inclusion of 1 other class, TestingUtils.class. This class looks like:

public class TestingUtils {

public static void setFieldValue( Object object, String fieldName, Object value ) {
    Field field = ReflectionUtils.findField( object.getClass(), fieldName );
    ReflectionUtils.makeAccessible( field );

    ReflectionUtils.setField( field, object, value );
}
}

All credits goes to the author of the blog.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文