As there is no RelayCommandAsync (at least not that I know of), how to test this scenario. For example:
public RelayCommand LoadJobCommand
{
get
{
return this.loadJobCommand ?? (
this.loadJobCommand =
new RelayCommand(
this.ExecuteLoadJobCommandAsync));
}
}
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
Test:
vm.LoadJobCommand.Execute()
Assert.IsTrue(vm.Jobs.Count > 0)
It really depends on what you are trying to test:
RelayCommand
is properly hooked up and calls your async
method?or
Async
Method logic is correct?1.a Using External Dependencies to verify
From my personal experience the easiest way to test that the trigger is wired up correctly to execute the command and then test that your class has interacted with another external class somewhere as expected. E.g.
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
private async void GetData(...)
{
var data = await _repo.GetData();
Jobs.Add(data);
}
Its fairly easy to test that your repo gets called.
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(Task.Run(() => 5))
.Verifiable();
_vm.LoadJobCommand.Execute(null);
_repo.VerifyAll();
}
I sometimes even do this, so that it doesn't try to process everything:
[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 Using a Scheduler
Another option is to use a scheduler, and schedule tasks using that.
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();
}
}
Then in your 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);
}
And your test
[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
LogicIf you are looking to test get GetData()
logic or even the ExecuteLoadJobCommandAsync()
logic. Then you should definitely make the method you want to test, as Internal, and mark your assmebly as InternalsVisibleTo
so that you can call those methods directly from your test class.
Why don't you cover GetData(...) method with tests? I don't see any sense in testing relay commands
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With