c# unit-testing mvvm prism delegatecommand

c# - Cómo Unit DelegateCommand que llama a métodos asíncronos en MVVM



unit-testing prism (3)

Soy nuevo en Unit Testing MVVM y uso PRISM en mi proyecto. Estoy implementando Pruebas unitarias en nuestro proyecto actual y no tengo suerte encontrando recursos en línea que me digan cómo funciona DelegateCommand que llama al método asincrónico. Esta es una pregunta de seguimiento para mi publicación: Cómo probar un modelo de vista con un método asíncrono. sobre cómo probar una unidad en un método asíncrono en MVVM y se respondió que los métodos públicos se pueden probar utilizando un método de prueba asíncrono. Este escenario funcionará solo si el método que deseo probar son métodos públicos.

El problema es que quiero probar mi DelegateCommand ya que estos son los únicos detalles públicos que quiero exponer en otras clases y todo lo demás es privado. Puedo exponer mis métodos privados como públicos, pero nunca haré esto porque es un mal diseño. No estoy seguro de cómo hacerlo. ¿Se debe probar DelegateCommand o hay algún otro trabajo al respecto? Estoy interesado en saber cómo otros hacen esto y de alguna manera me llevan al camino correcto.

Aquí están mis códigos otra vez

async void GetTasksAsync() { this.SimpleTasks.Clear(); Func<IList<ISimpleTask>> taskAction = () => { var result = this.dataService.GetTasks(); if (token.IsCancellationRequested) return null; return result; }; IsBusyTreeView = true; Task<IList<ISimpleTask>> getTasksTask = Task<IList<ISimpleTask>>.Factory.StartNew(taskAction, token); var l = await getTasksTask; // waits for getTasksTask if (l != null) { foreach (ISimpleTask t in l) { this.SimpleTasks.Add(t); // adds to ViewModel.SimpleTask } } }

También aquí está el comando en mi máquina virtual que llama al método asíncrono arriba

this.GetTasksCommand = new DelegateCommand(this.GetTasks); void GetTasks() { GetTasksAsync(); }

y ahora mi método de prueba es como

[TestMethod] public void Command_Test_GetTasksCommand() { MyViewModel.GetTaskCommand.Execute(); // this should populate ViewModel.SimpleTask Assert.IsTrue(MyBiewModel.SimpleTask != null) }

Actualmente, lo que obtengo es que mi ViewModel.SimpleTask = null es porque no espera a que termine el método async.


Como no puedo agregar comentarios, para completar, en PRISM 6 puedes probar:

ParsingCommand = new DelegateCommand<string>(async (x) => await StartParsing(x));


En Prism 6, puede crear DelegateCommand y DelegateCommand<T> desde el controlador async.

Por ejemplo:

startParsingCommand=DelegateCommand .FromAsyncHandler(StartParsingAsync,CanStartParsing) .ObservesProperty(()=> IsParserStarted);


Escribí una clase AsyncCommand que devuelve un objeto Task del método Execute . Luego debe implementar ICommand.Execute explicitamente, esperando la Tarea desde su implementación Execute :

public class AsyncCommand : ICommand { public event EventHandler CanExecuteChanged; public Func<Task> ExecutedHandler { get; private set; } public Func<bool> CanExecuteHandler { get; private set; } public AsyncCommand(Func<Task> executedHandler, Func<bool> canExecuteHandler = null) { if (executedHandler == null) { throw new ArgumentNullException("executedHandler"); } this.ExecutedHandler = executedHandler; this.CanExecuteHandler = canExecuteHandler; } public Task Execute() { return this.ExecutedHandler(); } public bool CanExecute() { return this.CanExecuteHandler == null || this.CanExecuteHandler(); } public void RaiseCanExecuteChanged() { if (this.CanExecuteChanged != null) { this.CanExecuteChanged(this, new EventArgs()); } } bool ICommand.CanExecute(object parameter) { return this.CanExecute(); } async void ICommand.Execute(object parameter) { await this.Execute(); } }

A continuación, puede pasar los métodos asincrónicos de devolución de tareas a la clase de comando:

public class ViewModel { public AsyncCommand AsyncCommand { get; private set; } public bool Executed { get; private set; } public ViewModel() { Executed = false; AsyncCommand = new AsyncCommand(Execute); } private async Task Execute() { await(Task.Delay(1000)); Executed = true; } }

En las pruebas de su unidad, simplemente espera el método Execute :

[TestMethod] public async Task TestAsyncCommand() { var viewModel = new ViewModel(); Assert.IsFalse(viewModel.Executed); await viewModel.AsyncCommand.Execute(); Assert.IsTrue(viewModel.Executed); }

La IU, por otro lado, llamará al método ICommand.Execute implementado explícitamente que se ocupa de la espera de la tarea.

(*) Mientras tanto, noté que si sigues las convenciones de nomenclatura comunes, el método de devolución de tareas debería llamarse ExecuteAsync .