Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test an async void method

Please consider the code as shown below. By calling GetBrands, property Brands will be assigned with proper data.

public class BrandsViewModel : ViewModelBase
{
    private IEnumerable<Brand> _brands;
    public IEnumerable<Brand> Brands
    {
        get { return _brands; }
        set { SetProperty(ref _brands, value); }
    }

    public async void GetBrands()
    {
        // ......

        Brands = await _dataHelper.GetFavoriteBrands();

        // ......
    }
}

But if I test it as shown below, the test failed. How do I wait for the async call inside method GetBrands?

[TestMethod]
public void AllBrandsTest()
{
    BrandsViewModel viewModel = new BrandsViewModel();
    viewModel.GetBrands();
    Assert.IsTrue(viewModel.Brands.Any());
}
like image 868
Shinbo Avatar asked Oct 17 '25 19:10

Shinbo


1 Answers

The simple answer here is: don't make it an async void. In fact, don't ever make something an async void unless it absolutely has to be to work as an event-handler. The things that async void loses are precisely the things that you want here for your test (and presumably for your real code).

Make it an async Task method instead, and you now have the ability to wait for completion (with timeout) / add a continuation, and to check whether it exited with success or an exception.

This is a single word change, to:

public async Task GetBrands()
{
    // ......

    Brands = await _dataHelper.GetFavoriteBrands();

    // ......
}

and then in the test:

[TestMethod]
public async Task AllBrandsTest()
{
    BrandsViewModel viewModel = new BrandsViewModel();
    var task = viewModel.GetBrands();
    Assert.IsTrue(task.Wait(YOUR_TIMEOUT), "failed to load in time");
    Assert.IsTrue(viewModel.Brands.Any(), "no brands");
}
like image 119
Marc Gravell Avatar answered Oct 20 '25 07:10

Marc Gravell