【问题标题】:How junit this observable async method如何junit这个可观察的异步方法
【发布时间】:2026-02-16 23:45:01
【问题描述】:

我有一个使用 java8 和响应式测试异步执行的存储库:

zadd 的接口:

Observable<Long> zadd(K key, double score, V member);



 public class TargetClass()
{
..
     public void executeMethod(List<String> input) {
            input.forEach(item -> redisConnection.reactive().zadd(...).subscribe(
                    result -> log.info("Success")
                    error -> log.error("Failed...")
            ));
        }
..
}

我的junit测试代码:

@Test
public void testMethod() {
  TargetClass targetClass=new TargetClass();
    targetClass.executeMethod(Arrays.asList("input1", "input2", "input3"));

    //as you can see I must put here Thread.sleep in order to let my execution to finish before continue since we have dependency on it

    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //continue with testing..

如何修改我的代码部分权限。添加Thread.sleep让异步方法代码发生感觉不太对

谢谢, 射线。

【问题讨论】:

  • @the8472 我知道未来。你能添加一个相关的例子吗?

标签: java java-8 reactive-programming observable lettuce


【解决方案1】:

如果我是你,我会通过添加 2 个新参数来重载方法 executeMethod,一个参数将是在 success 上执行的函数,另一个是在 failure 上执行的函数。我将创建新方法protected 而不是public,我将在我的单元测试中测试这个新方法而不是另一个。你的public 方法可以用这个executeMethod(input, result -&gt; log.info("Success"), error -&gt; log.error("Failed...")) 调用新的方法。在我的单元测试中,我可以提供一种方法来获得这样的结果:

@Test
public void testMethod() {
    TargetClass targetClass = new TargetClass();
    AtomicBoolean success = new AtomicBoolean();
    synchronized (success) {
        targetClass.executeMethod(
            list, 
            result -> {
                synchronized (success) {
                    success.set(true);
                    success.notify();
                } 
            }, 
            error -> {
                synchronized (success) {
                    success.set(false);
                    success.notify();
                } 
            }
        );
        success.wait();
    }
    // The rest of your unit test here
}

【讨论】:

  • 你会在哪里覆盖它?在我的目标班上?那是那个类的样板代码不是吗?我将以这种态度在我的目标类上复制我所有的方法
  • 在你的实现类中。顺便说一句,我建议 overload 不要覆盖,这是两个不同的概念。
  • 我知道重载的意思。在那种情况下,您仍然为单元测试目的添加“样板”代码(重载每个方法),感觉有点不对
  • 我不这么认为,对我来说如果你不能对自己的类进行单元测试,那更多的是设计问题,也许你应该重新审查你的设计。无论如何,我不明白你不喜欢这种方法的什么,但我相信它仍然比单次睡眠要好,而且你如何用你的方法得到结果?
  • 即使是预设,你也需要回调才能知道你的环境什么时候准备好,我提出的是一种获取回调的方法。 BTW 如果是预设,可以考虑把这部分代码移到一个用@Before注解的方法中