有没有办法对异步方法进行单元测试?

发布于 2024-07-29 03:49:51 字数 193 浏览 10 评论 0原文

我在 .NET 平台上使用 Xunit 和 NMock。 我正在测试一个表示模型,其中方法是异步的。 该方法创建一个异步任务并执行它,以便该方法立即返回,并且我需要检查的状态尚未准备好。

我可以在完成时设置一个标志而不修改 SUT,但这意味着我必须在 while 循环中继续检查该标志,例如,可能会超时。

我有什么选择?

I am using Xunit and NMock on .NET platform.
I am testing a presentation model where a method is asynchronous.
The method creates an async task and executes it so the method returns immediately and the state I need to check aren't ready yet.

I can set a flag upon finish without modifying the SUT but that would mean I would have to keep checking the flag in a while loop for example, with perhaps timeout.

What are my options?

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

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

发布评论

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

评论(5

奈何桥上唱咆哮 2024-08-05 03:49:51

只是认为您可能需要对此进行更新,因为#1 答案实际上是推荐一种较旧的模式来解决此问题。

在 .net 4.5 + xUnit 1.9 或更高版本中,您可以简单地返回一个任务,并可以选择使用测试中的 async 关键字让 xunit 等待测试异步完成。

请参阅有关 xUnit.net 1.9 的文章

[Fact]
public async Task MyAsyncUnitTest()
{    
  // ... setup code here ...     
  var result = await CallMyAsyncApi(...);     
  // ... assertions here ...
}

Just thought you might want an update on this since the #1 answer is actually recommending an older pattern to solve this problem.

In .net 4.5 + xUnit 1.9 or higher you can simply return a Task and optionally use the async keyword from your test to have xunit wait for the test to complete asynchronously.

See this article on xUnit.net 1.9

[Fact]
public async Task MyAsyncUnitTest()
{    
  // ... setup code here ...     
  var result = await CallMyAsyncApi(...);     
  // ... assertions here ...
}
2024-08-05 03:49:51

您的对象是否具有异步方法完成的任何类型的信号,例如事件? 如果是这种情况,您可以使用以下方法:

[Test]
public void CanTestAsync()
{
    MyObject instance = new MyObject()
    AutoResetEvent waitHandle = new AutoResetEvent(false); 
    // create and attach event handler for the "Finished" event
    EventHandler eventHandler = delegate(object sender, EventArgs e) 
    {
        waitHandle.Set();  // signal that the finished event was raised
    } 
    instance.AsyncMethodFinished += eventHandler;

    // call the async method
    instance.CallAsyncMethod();

    // Wait until the event handler is invoked
    if (!waitHandle.WaitOne(5000, false))  
    {  
        Assert.Fail("Test timed out.");  
    }  
    instance.AsyncMethodFinished -= eventHandler;    
    Assert.AreEqual("expected", instance.ValueToCheck);
}

Does your object feature any sort of signal that the asynchronous method is finished, such as an event? If that is the case, you can use the following approach:

[Test]
public void CanTestAsync()
{
    MyObject instance = new MyObject()
    AutoResetEvent waitHandle = new AutoResetEvent(false); 
    // create and attach event handler for the "Finished" event
    EventHandler eventHandler = delegate(object sender, EventArgs e) 
    {
        waitHandle.Set();  // signal that the finished event was raised
    } 
    instance.AsyncMethodFinished += eventHandler;

    // call the async method
    instance.CallAsyncMethod();

    // Wait until the event handler is invoked
    if (!waitHandle.WaitOne(5000, false))  
    {  
        Assert.Fail("Test timed out.");  
    }  
    instance.AsyncMethodFinished -= eventHandler;    
    Assert.AreEqual("expected", instance.ValueToCheck);
}
深海夜未眠 2024-08-05 03:49:51

我的首选方法是模拟并注入实际的线程机制,以便在测试时它不是异步的。 有时这是不可能的(如果方法的线程是框架的一部分,或者不在您的控制之下)。

如果您无法控制线程创建,则等待线程以某种方式完成,无论是 while 循环还是只是定时等待线程应该花费的时间,如果状态不存在,则测试失败无论如何花了太长时间。

My preferred method is to mock out and inject the actual threading mechanism so that under test it is not asynchronous. Some times that is not possible (if the threading of the method is part of the framework, or otherwise not under your control).

If you can't control thread creation, then waiting for the thread to finish in some way, either a while loop or just a timed wait for however long the thread is supposed to take and failing the test if the state is not there since it took too long anyway.

森林迷了鹿 2024-08-05 03:49:51

查看我关于 Silverlight 应用程序单元测试的文章

http://www.codeproject.com/KB /silverlight/Ag3DemoLOB.aspx

有一个对异步调用 WCF 服务的方法进行单元测试的示例...

check out my article on unit testing Silverlight applications

http://www.codeproject.com/KB/silverlight/Ag3DemoLOB.aspx

There is an example of unit testing a method that calls a WCF service asynchronously...

硬不硬你别怂 2024-08-05 03:49:51

使用 NSubtitute 和 XUnit 进行异步测试实际上非常简单:

 public interface IA
{
    Task<int> DoSomething();
}

调用者:

 public class IAmUnderTest
{
    public async Task<int> GetInt(IA a)
    {
        return await a.DoSomething();
    }
}

因为异步方法仅返回任务,所以使用 NSubstitute 模拟 DoSomething() 所需要做的就是使用 Task.FromResult()。 然后调用代码返回一个任务,它仍然可以等待并返回整数结果。

因此,使用 NSubstitute 模拟它看起来像这样:

  public class ATest
{
    [Fact]
    public void DoesSomething()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = target.GetInt(dependency).Result;

        id.Should().Be(1);
    }
}

通过使测试异步添加一点额外的内容:

  public class ATest
{
    [Fact]
    public async Task DoesSomethingAsync()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = await target.GetInt(dependency);

        id.Should().Be(1);
    }
}

在测试异步方法时,后者比前者更受青睐。

归功于:https://www.garethrepton.com/Unit-Testing-async-methods/#:~:text=因为%20Async%20methods%20just%20return%20tasks%2C%20all%20you,所以%20mocking%20it%20用%20NSubstitute%20looks%20like%20this%3A

Async Tests with NSubtitute and XUnit are actually pretty straight forward:

 public interface IA
{
    Task<int> DoSomething();
}

called by:

 public class IAmUnderTest
{
    public async Task<int> GetInt(IA a)
    {
        return await a.DoSomething();
    }
}

Because Async methods just return tasks, all you need to do to mock DoSomething() with NSubstitute is use Task.FromResult(). Then the calling code gets a task back that it can still await and get back the integer result.

So mocking it with NSubstitute looks like this:

  public class ATest
{
    [Fact]
    public void DoesSomething()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = target.GetInt(dependency).Result;

        id.Should().Be(1);
    }
}

Adding a little extra by making the test async:

  public class ATest
{
    [Fact]
    public async Task DoesSomethingAsync()
    {
        var dependency = Substitute.For<IA>();
        dependency.DoSomething().Returns(Task.FromResult(1));

        var target = new IAmUnderTest();
        var id = await target.GetInt(dependency);

        id.Should().Be(1);
    }
}

The latter is favoured over the former when testing async methods.

Credit to: https://www.garethrepton.com/Unit-Testing-async-methods/#:~:text=Because%20Async%20methods%20just%20return%20tasks%2C%20all%20you,So%20mocking%20it%20with%20NSubstitute%20looks%20like%20this%3A

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