如何对回调逻辑进行单元测试?

发布于 2024-11-30 19:24:27 字数 549 浏览 2 评论 0原文

更完整的问题是,给定一个需要回调作为参数的依赖项,我如何编写一个涵盖回调逻辑的单元测试,并且仍然设法模拟依赖项?

public class DoStuff {
    public void runThis(Runnable callback) {
        // call callback
    }
}

public class ClassUnderTest {
    private DoStuff stuffToDo;

    public void methodUnderTest() {
        this.stuffToDo.runThis(/*a runnable with some logic*/)
    }
}

在上面的示例中,我将模拟 stuffToDo 因为我应该验证方法调用的调用和模拟输出。但是,模拟 runThis 会导致回调逻辑未被测试。此外,回调逻辑似乎应该是私有的,所以我不希望直接测试它;也许这是我的一个误解。

由于回调的使用相当广泛,我希望有一个通用的方法来测试它们,但我还没有找到。

More complete question is, given a dependency that expects a callback as a parameter, how do I write a unit test that covers the callback logic and still manage to mock up the dependency?

public class DoStuff {
    public void runThis(Runnable callback) {
        // call callback
    }
}

public class ClassUnderTest {
    private DoStuff stuffToDo;

    public void methodUnderTest() {
        this.stuffToDo.runThis(/*a runnable with some logic*/)
    }
}

In the example above, I would mock stuffToDo since I should verify calls and mock outputs of method calls. However, mocking runThis results in the callback logic not being tested. Furthermore, callback logic seems like it should be private so I wouldn't expect to test it directly; perhaps that is a misconception on my part.

Since callbacks are used rather extensivly, I would expect there to be a common method for testing them but I haven't found it.

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

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

发布评论

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

评论(5

葬花如无物 2024-12-07 19:24:27

你不能在一次测试中。如果您模拟某些东西,它就会被模拟,这意味着它只能验证参数并模拟返回值(您在测试中配置)。

事实上,模拟某些东西的全部目的是测试单独使用模拟的内容。如果您想要对 DoStuff 进行单元测试,您不必担心使用某些可能有效或无效的回调实现。您模拟了回调,因此您不必担心它。

您仍然可以通过单独测试回调代码,并单独测试回调用户(使用回调的模拟)来进行良好的测试,并且可能通过进行集成测试来进行良好的测量,您可以在其中进行集成测试。将完全配置的组件作为一个整体使用。

You can't in a single test. If you mock something, its mocked, meaning it can only verify arguments and simulate return values (that you configure in the test).

Indeed, the entire point of mocking something is to test what uses the mock in isolation. If you want a unit test of DoStuff, you don't want to have to worry about using some callback implementation that might or might not be working. You mock the callback so you don't have to worry about it.

You can still have good tests by testing the callback code in isolation, and testing the callback user in isolation (using a mock for the callback) and perhaps by throwing an integration test in for good measure, where you use the fully configured component as a whole.

苦妄 2024-12-07 19:24:27

基本上,您想要测试 DoStuff 类。这意味着您需要取消测试 DoStuff 中的所有方法,对吧?因此,在这种情况下,您需要做的是,不要模拟 stuffToDo 本身,而是将模拟的 Runnable 注入 到 stuffToDo 中。然后检查你的runnable是否成功执行。

但是,如果您在类中确实有其他功能,您可能需要单独测试并模拟它们。

Here basically you want to test the class DoStuff. That means you need to unti-test all the methods inside DoStuff, right?. So in this case, what you need to do is, instead of mocking stuffToDo itself, inject a mocked Runnable into stuffToDo. And then check whether your runnable was successfully executed or not.

But if you do have other functionalities in the class, you may have separate test and mock them out.

祁梦 2024-12-07 19:24:27

在您的特定情况下,听起来您已经测试了 DoStuff (或者不再关心它,因为它被模拟了),现在正在专门对特定的 Runnable 进行单元测试你设计的。在这种情况下,回调听起来正是您想要测试的内容,就像有人可能想要直接对数据库策略或内存策略进行专门的单元测试一样。

如果这是您正在尝试的,您可以在黑匣子中测试它,并尽可能通过 ClassUnderTest 进行练习。或者您可以在特定的 Runnable 上创建测试工具。如果您要发布此代码并且不想使测试工具可访问,则可以将测试工具方法设为私有,并专门与单元测试程序集共享其详细信息。

有关如何创建友元程序集的信息,请参阅此处。我通常会对单元测试代码进行签名,这样我就不必使用命令行编译器了。我想这取决于你的构建环境。

In your particular case, it sounds like you've already tested DoStuff (or don't care anymore since it is mocked) and now are specifically unit-testing a specific Runnable you've designed. In this case, callback sounds like exactly what you want to be testing, in the same manner someone might want to specifically unit-test a database strategy or in-memory strategy directly.

If this is what you are attempting, either you can test it in a black box, exercising it through ClassUnderTest as best as you can. Or you can create a testing harness on your particular Runnable. If you are releasing this code and don't want to make your testing harness reachable, you can make the test harness methods private and share its details specifically with your unit test assembly.

Look here for information about how to make friend assemblies. I typically sign my unit test code so that I don't have to muck with a command line compiler. I suppose it depends on your build environment.

家住魔仙堡 2024-12-07 19:24:27

一个只无条件调用 Runnable 的假 DoStuff 怎么样?

然后,您只需感知效果 - 如果您的回调被执行,应该观察到的变化。

How about a fake DoStuff that just invokes the Runnable unconditionally ?

Then you just sense for the effects - changes that should be observed if your callback was executed.

你对谁都笑 2024-12-07 19:24:27

如果您使用 EasyMock,您可以使用 andStubAnswer 来调用可运行的。

doSomethingMock.runThis(runnable);
expectLastCall().andStubAnswer(new IAnserable<Void>() {
   Runnable runnable = (Runnable)getCurrentArguments()[0];
   runnable.run();
   return null;
});

我想其他模拟框架也包含类似的东西。

If your using EasyMock, you can use andStubAnswer to call the runnable.

doSomethingMock.runThis(runnable);
expectLastCall().andStubAnswer(new IAnserable<Void>() {
   Runnable runnable = (Runnable)getCurrentArguments()[0];
   runnable.run();
   return null;
});

I imagine other mocking frameworks contain something similar.

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