由于没有RelayCommandAsync(至少不是我所知道的),如何测试这种情况。例如:
public RelayCommand LoadJobCommand
{
get
{
return this.loadJobCommand ?? (
this.loadJobCommand =
new RelayCommand(
this.ExecuteLoadJobCommandAsync));
}
}
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
测试:
vm.LoadJobCommand.Execute()
Assert.IsTrue(vm.Jobs.Count > 0)
答案 0 :(得分:1)
我没有使用async / await,但我过去遇到过类似的问题。我所处的情况是本身内部称为Task.Run(
的方法,单元测试验证ViewModel使用正确的参数以正确的次数调用服务。
我们解决这个问题的方式是我们使用了ManualResetEventSlim
来调用服务的Mock,然后单元测试等待在继续之前调用该重置事件。
[TestMethod]
public void EXAMPLE()
{
using (var container = new UnityAutoMoqContainer())
{
//(SNIP)
var serviceMock = container.GetMock<ITreatmentPlanService>();
var resetEvent = new ManualResetEventSlim();
serviceMock.Setup(x=>x.GetSinglePatientViewTable(dateWindow, currentPatient, false))
.Returns(() =>
{
resetEvent.Set();
return new ObservableCollection<SinglePatientViewDataRow>();
});
var viewModel = container.Resolve<SinglePatientViewModel>();
//(SNIP)
viewModel.PatientsHadTPClosed(guids, Guid.NewGuid());
waited = resetEvent.Wait(timeout);
if(!waited)
Assert.Fail("GetSinglePatientViewTable was not called within the timeout of {0} ms", timeout);
//(SNIP)
serviceMock.Verify(x => x.GetSinglePatientViewTable(dateWindow, currentPatient, false), Times.Once);
}
}
如果这种方法对您有效或无效,则取决于您的单元测试实际测试的内容。因为您检查Assert.IsTrue(vm.Jobs.Count > 0)
,看起来您在await GetData(...);
调用后有额外的逻辑,所以这可能不适用于您当前的问题。但是,这可能对您需要为视图模型编写的其他单元测试有所帮助。
答案 1 :(得分:1)
这实际上取决于你要测试的内容:
RelayCommand
是否已正确连接并调用async
方法或
Async
方法逻辑是否正确?1.a使用外部依赖关系验证
根据我的个人经验,最简单的方法是测试触发器是否正确连接以执行命令,然后测试您的类是否按预期在某处与另一个外部类进行了交互。 E.g。
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
private async void GetData(...)
{
var data = await _repo.GetData();
Jobs.Add(data);
}
很容易测试你的回购被调用。
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(Task.Run(() => 5))
.Verifiable();
_vm.LoadJobCommand.Execute(null);
_repo.VerifyAll();
}
我有时甚至会这样做,所以它不会尝试处理所有事情:
[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();
}
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();
}
}
然后在你的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);
}
你的考试
[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();
}
GetData
逻辑如果您要测试get GetData()
逻辑或甚至ExecuteLoadJobCommandAsync()
逻辑。那么你一定要把你想要测试的方法作为内部,并将你的方法标记为InternalsVisibleTo
,这样你就可以直接从测试类中调用这些方法。
答案 2 :(得分:0)
为什么不用测试覆盖GetData(...)方法?我认为测试继电器命令没有任何意义