4

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()); } 
2
  • 3
    Please read / view this: blogs.msdn.com/b/lucian/archive/2013/02/18/… It basically says: Don't use async void except for event handlers. Commented Mar 21, 2013 at 7:53
  • @DanielHilgarth Thank you, Daniel. I refactored my code, and it just work like a charm. Commented Mar 21, 2013 at 10:38

2 Answers 2

9

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"); } 
Sign up to request clarification or add additional context in comments.

3 Comments

Why did you keep the test async, if you don't use await in it?
@svick that is a question for the OP, who also doesn't await in it :)
@svick My fault. I have corrected my test code. It's not necessary to keep async if no await in the method.
1

Your model (a DTO) is populating itself (data access). This is too much for one class to do. Usually when you ask yourself "How on earth can I test this", it's time for refactoring. Create a separate data access class:

BrandsViewModel viewModel = new BrandsViewModel(); var brandAccess = new BrandsDataAccess(); viewModel.Brands = await brandAccess.GetAllBrands(); Assert.IsTrue(viewModel.Brands.Any()); 

Now you can test BrandsDataAccess.GetAllBrands().

5 Comments

Where did async go? What I mean: the original code is async, yours isn't, so I don't think it's a good replacement.
@svick it's the principle that matters, not the implementation. See edit.
@CodeCaster Would you please explain your point further more? In terms of Single Responsibility Principle, I think populate its own property within the same class is acceptable. Isn't it?
@Shinbo no, a data transfer object (which a (view)model is) should not be concerned with data access.
@CodeCaster Thanks for clarifying it. What is the side effect if a DTO contains data access logic?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.