【问题标题】:How to run method synchronously from test project (no await)如何从测试项目同步运行方法(无等待)
【发布时间】:2017-10-11 08:26:33
【问题描述】:

我在使用 Task 和围绕它的整个概念方面非常陌生。我也在使用 Net 4.0Office 2007 的 VSTO 开发

我想了解我在我的应用程序中写的一件事,它正在生产中,但为它编写单元测试最终使用Thread.Sleep 并检查任务是否运行完成

背景

生产代码非常简单,它调用一个服务来检查环境状态(PROD、STAGE、QA 等)它是通过 Task 在 (void) 方法中完成的,在 Task 正文中,它设置了一个正在更新 UI (WPF) 的属性,并且工作正常。请注意,我没有在该方法中使用 Wait。如果任务失败,我会使用 OnlyOnFaulted

继续另一个任务

问题

我尝试对方法 (void) 进行单元测试,因此我想运行 同步 运行的方法,但我在那里失败了。 我读到了RunSynchronously,也看到人们使用任务。Result这似乎不适用于 4.0),还尝试了Scheduler.Current,@ 987654329@等

我认为问题出在我的设计上,我想我正在尝试调用一个方法并说“嘿,同步运行”并且确实如此,但在方法内部是另一个运行异步的任务,所以无论如何它都会运行异步的。我对吗?有没有办法在我的测试项目中没有循环并等待RunToCompletion 来测试它?

这是我为更好地理解而创建的示例代码,我对其进行了一些简化。在实际实施中,我的解决方案中有一个适当的测试项目,我正在模拟该服务,因此它不会调用真实的服务等。

namespace ConsoleApplication1
{
public class Program
{
    static void Main(string[] args)
    {
        ImagineThisIsInTestProject();
        Console.ReadLine();

        Console.WriteLine("Started");
        var cls = new Program();
        cls.MyProdMethod();
        Console.WriteLine("Finished");
        Console.ReadLine();
    }

    public string Status { get; private set; }

    public void MyProdMethod()
    {
        // I have more logic in my real method, serialization, handling errors
        Console.WriteLine("In my method");
        var task = Task.Factory.StartNew(() => {
                        Thread.Sleep(2000);
                        Console.WriteLine("Setting status");
                        Status = "Yes I set it";
                        }, CancellationToken.None);
        Console.WriteLine("Finishing my method");
    }

    public static void ImagineThisIsInTestProject()
    {
        Console.WriteLine("TEST started");
        var sut = new Program();
        var task = new Task(() => sut.MyProdMethod());
        task.RunSynchronously(); // I would assume this will wait until the task is finished?

        // here my assert if status is set
        Console.WriteLine($"Status is - {sut.Status}");
        Console.WriteLine("TEST finished");
    }
}
}

上面的输出是

TEST started
In my method
Finishing my method
Status is -
TEST finished
Setting status

Started
In my method
Finishing my method
Finished
Setting status

【问题讨论】:

  • 你使用什么单元测试框架?大多数(正在积极开发的)已更新以理解和支持async 测试。
  • 啊抱歉 Visual Studio,所以我猜它是 MS 测试,用于模拟起订量。和 VS 2015,但目标是 4.0

标签: c# unit-testing .net-4.0 task-parallel-library


【解决方案1】:

你不能真正测试你的方法public void MyProdMethod(),因为:

var task = Task.Factory.StartNew(() => {
                    Thread.Sleep(2000);
                    Console.WriteLine("Setting status");
                    Status = "Yes I set it";
                    }, CancellationToken.None);

基本上是火了就忘了

除非您等待任务完成,否则无法对此进行测试。我知道您不想包含 Wait,但要测试考虑以下内容:

    public void MyProdMethod()
    {
        // I have more logic in my real method, serialization, handling errors
        Console.WriteLine("In my method");
        Task.Factory.StartNew(() => {
            Thread.Sleep(2000);
            Console.WriteLine("Setting status");
            Status = "Yes I set it";
        }, CancellationToken.None).Wait();

        Console.WriteLine("Finishing my method");
    }

然后您的测试将如下所示:

[TestClass]
public class TestClass
{
    [TestMethod]
    public void Test()
    {
        // Arrange
        var program = new Program();

        // Act
        program.MyProdMethod();

        // Assert
        Assert.AreEqual("Yes I set it", program.Status);
    }

}

如果您取消 Wait,测试将在方法中的 Task 有机会完成之前完成,因此导致 Assert 失败。

【讨论】:

  • Task @ODawg G,有趣的是我在生产代码中尝试了它并得到了一个异常“任务被取消”但 prod 方法略有不同,它继续使用处理错误的方法,就像这里 - .ContinueWith(failedTask => HandleTaskError(failedTask), TaskContinuationOptions.OnlyOnFaulted);我会用我在这里发送的示例代码在家尝试
  • 好的,我明白了 Wait() 不起作用的原因 - 我将任务返回给一个似乎不可能的变量。我删除了它(老实说我不需要它,我可能正在测试一些东西)然后我可以申请 Wait 但这会阻止运行代码,在我的情况下会阻止 UI。我将阅读更多关于 ContinueWith 的信息,这似乎是实现我想要的方式 - 运行异步操作而不阻塞 UI
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 2017-04-30
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多