Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Unit Test a void method with a Task inside

I have a graphic method CancelChanges() used and called by a ViewModel. I want to test this method but we have a Task inside. We use a Task to not freeze the UI. My test method needs to wait the result of this Task to check the result.

The code is:

public override void CancelChanges()
{
        Task.Run(
            async () =>
                {
                    this.SelectedWorkflow = null;
                    AsyncResult<IncidentTypeModel> asyncResult = await this.Dataprovider.GetIncidentTypeByIdAsync(this.Incident.Id);

                    Utils.GetDispatcher().Invoke(
                        () =>
                            {
                                if (asyncResult.IsError)
                                {
                                    WorkflowMessageBox.ShowException(
                                        MessageHelper.ManageException(asyncResult.Exception));
                                }
                                else
                                {
                                    this.Incident = asyncResult.Result;
                                    this.Refreshdesigner();
                                    this.HaveChanges = false;
                                }
                            });
                });
}

And my test method:

/// <summary>
///     A test for CancelChanges
/// </summary>
[TestMethod]
[TestCategory("ConfigTool")]
public void CancelChangesTest()
{
    string storexaml = this._target.Incident.WorkflowXamlString;
    this._target.Incident.WorkflowXamlString = "dsdfsdgfdsgdfgfd";

    this._target.CancelChanges();

    Assert.IsTrue(storexaml == this._target.Incident.WorkflowXamlString);
    Assert.IsFalse(this._target.HaveChanges);
}

How can we do to have my test that is waiting the result of the Task?

Thanks.

like image 550
Adrien Avatar asked Dec 25 '22 08:12

Adrien


2 Answers

Make the CancelChanges method return a Task, and then await this or set up a continuation in the test method. Some this like

public override Task CancelChanges()
{
    return Task.Factory.StartNew(() =>
        {
            // Do stuff...
        });
}

notice the change from Task.Run to Task.Factory.StartNew. This is a better way of starting tasks in such cases. Then in the test method

[TestMethod]
[TestCategory("ConfigTool")]
public void CancelChangesTest()
{
    string storexaml = this._target.Incident.WorkflowXamlString;
    this._target.Incident.WorkflowXamlString = "dsdfsdgfdsgdfgfd";
    this._target.CancelChanges().ContinueWith(ant => 
        {
            Assert.IsTrue(storexaml == this._target.Incident.WorkflowXamlString);
            Assert.IsFalse(this._target.HaveChanges);
        });
}

You could also mark the test method as async and use await in the test method to do the same thing.

I hope this helps.

like image 86
MoonKnight Avatar answered Dec 28 '22 11:12

MoonKnight


I would take the refactoring one step further, and if possible avoid using Task.Run. Since all you do is await and then invoke work on the UI Thread, I would do the following:

public override Task CancelChanges()
{
     this.SelectedWorkflow = null;
     AsyncResult<IncidentTypeModel> asyncResult =       await    this.Dataprovider.GetIncidentTypeByIdAsync(this.Incident.Id);
     if (asyncResult.IsError)
     {          WorkflowMessageBox.ShowException(MessageHelper.ManageException(asyncResult.Exception));
     }        
    else
    {
         this.Incident = asyncResult.Result;
         this.Refreshdesigner();
         this.HaveChanges = false;
     }
   });
 });
}

And the test method:

[TestMethod]
[TestCategory("ConfigTool")]
public async Task CancelChangesTest()
{
  string storexaml =   this._target.Incident.WorkflowXamlString;
  this._target.Incident.WorkflowXamlString = "dsdfsdgfdsgdfgfd";

  var cancelChanges = await  this._target.CancelChanges();

  Assert.IsTrue(storexaml == this._target.Incident.WorkflowXamlString);
  Assert.IsFalse(this._target.HaveChanges);
}
like image 20
Yuval Itzchakov Avatar answered Dec 28 '22 10:12

Yuval Itzchakov