如何单元测试执行异步方法的RelayCommand?

O.O*_*O.O 6 c# unit-testing asynchronous mvvm-light .net-4.5.2

由于没有RelayCommandAsync(至少不是我所知道的),如何测试这种情况.例如:

public RelayCommand LoadJobCommand
{
    get
    {
        return this.loadJobCommand ?? (
            this.loadJobCommand =
            new RelayCommand(
                this.ExecuteLoadJobCommandAsync));
    }
}

private async void ExecuteLoadJobCommandAsync()
{
   await GetData(...);
}
Run Code Online (Sandbox Code Playgroud)

测试:

vm.LoadJobCommand.Execute()

Assert.IsTrue(vm.Jobs.Count > 0)
Run Code Online (Sandbox Code Playgroud)

Mic*_*han 1

这实际上取决于您要测试的内容:

  1. 测试是否RelayCommand正确连接并调用您的async 方法?

或者

  1. 测试Async方法逻辑是否正确?

1. 测试RelayCommand触发器

1.a 使用外部依赖来验证

根据我个人的经验,测试触发器是否正确连接以执行命令,然后测试您的类是否已按预期与另一个外部类交互的最简单方法。例如

private async void ExecuteLoadJobCommandAsync()
{
   await GetData(...);
}

private async void GetData(...)
{
   var data = await _repo.GetData();
   Jobs.Add(data);
}
Run Code Online (Sandbox Code Playgroud)

测试您的存储库是否被调用相当容易。

    public void TestUsingExternalDependency()
    {
        _repo.Setup(r => r.GetData())
            .Returns(Task.Run(() => 5))
            .Verifiable();

        _vm.LoadJobCommand.Execute(null);

        _repo.VerifyAll();
    }
Run Code Online (Sandbox Code Playgroud)

我有时甚至这样做,这样它就不会尝试处理所有内容:

    [Test]
    public void TestUsingExternalDependency()
    {
        _repo.Setup(r => r.GetData())
            .Returns(() => { throw new Exception("TEST"); })
            .Verifiable();

        try
        {
            _vm.LoadJobCommand.Execute(null);
        }
        catch (Exception e)
        {
            e.Message.Should().Be("TEST");
        }

        _repo.VerifyAll();
    }
Run Code Online (Sandbox Code Playgroud)

1.b 使用调度程序

另一种选择是使用调度程序,并使用它来安排任务。

public interface IScheduler
{
    void Execute(Action action);
}

// Injected when not under test
public class ThreadPoolScheduler : IScheduler
{
    public void Execute(Action action)
    {
        Task.Run(action);
    }
}

// Used for testing
public class ImmediateScheduler : IScheduler
{
    public void Execute(Action action)
    {
        action();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的 ViewModel 中

    public ViewModelUnderTest(IRepository repo, IScheduler scheduler)
    {
        _repo = repo;
        _scheduler = scheduler;
        LoadJobCommand = new RelayCommand(ExecuteLoadJobCommandAsync);
    }
    private void ExecuteLoadJobCommandAsync()
    {
        _scheduler.Execute(GetData);

    }

    private void GetData()
    {
        var a =  _repo.GetData().Result;
        Jobs.Add(a);
    }
Run Code Online (Sandbox Code Playgroud)

还有你的测试

    [Test]
    public void TestUsingScheduler()
    {
        _repo.Setup(r => r.GetData()).Returns(Task.Run(() => 2));

        _vm = new ViewModelUnderTest(_repo.Object, new ImmediateScheduler());

        _vm.LoadJobCommand.Execute(null);

        _vm.Jobs.Should().NotBeEmpty();
    }
Run Code Online (Sandbox Code Playgroud)

2. 测试GetData逻辑

如果您想测试GetData()逻辑甚至ExecuteLoadJobCommandAsync()逻辑。然后,您绝对应该将要测试的方法设置为Internal,并将您的程序集标记为,InternalsVisibleTo以便您可以直接从测试类调用这些方法。