# Testing async method call from constructor

I have a project where I want to build a more sophisticated ToDo list - basically a personal project management system. I'm just starting out with the project, and I'd like some feedback on whether my test methods are OK, as I'm pretty new to TDD. So far, for the main page that lists the daily ToDo items, I've got the following ViewModel:

public class MainVM : ViewModelBase
{
private IEnumerable<ToDoItem> _toDoItems;
private IRepository<ToDoItem> _toDoItemRepo;

{
set { Set(ref _dataIsLoaded, value, true); }
}

public IEnumerable<ToDoItem> ToDoItems
{
get { return _toDoItems; }
set { Set(ref _toDoItems, value); }
}

public MainVM(IRepository<ToDoItem> toDoItemRepo)
{
_toDoItemRepo= toDoItemRepo;
}

{
{
break;
default:
break;
}
}

{
ToDoItems= await _toDoItemRepo.GetAsync();
}
}


As you can see, I want to load my data when the ViewModel is created.

I'm using the Set method from the MVVMLight toolkit to set the DataIsLoaded property- it sets the field behind and raises the PropertyChanged event for me.

I have the following test set up to test for a successful load:

    public void DataIsLoaded_is_true_if_loading_task_ran_to_completion()
{
AutoResetEvent testTrigger = new AutoResetEvent(false);

Mock<IRepository<ToDoItem>> repoMock = new Mock<IRepository<ToDoItem>>();

MainVM vm = new MainVM(repoMock.Object);
vm.PropertyChanged += (s, e) =>
{
testTrigger.Set();
};

testTrigger.WaitOne(5000);

}


Now, I can see that there is a potential race condition here. The LoadData method could complete before the event handler is attached. As an alternative, I could use the Set method that broadcasts a message to MVVMLight's message handler in my ViewModel, and change my test method to this:

    [Test]
{
AutoResetEvent testTrigger = new AutoResetEvent(false);

Mock<IRepository<ToDoItem>> repoMock = new Mock<IRepository<ToDoItem>>();

Messenger.Default.Register<PropertyChangedMessage<bool>>(
this,
message =>
{
{
testTrigger.Set();
}
});
MainVM vm = new MainVM(repoMock.Object);

testTrigger.WaitOne(5000);

}


Now I don't have a race condition, but I'm a bit annoyed that I'm broadcasting a message that I don't really need for my code to work. I could wrap the whole thing in an pre-processor directive, of course, but that's just clunky.

Is there a better way to go about the whole thing?

• The code I posted is actual code, however. I wasn't sure what I wanted to call my Model, so initially I just called it Thingy, not realising that that would be considered pseudocode. I have edited my question with a better name for my Model class. – Frauke Mar 1 '18 at 22:44

Trying to load the data asynchronously in the constructor is a bad idea and in my opinion goes against what the constructor is for.

Constructors cannot be async, and asynchronous initialization can be seen as an implementation detail.

public class MainVM : ViewModelBase {
private IEnumerable<ToDoItem> items;

set { Set(ref _dataIsLoaded, value, true); }
}

public IEnumerable<ToDoItem> ToDoItems {
get { return items; }
set { Set(ref items, value); }
}

public MainVM(IRepository<ToDoItem> repository) {
this.repository = repository;
}

try {
ToDoItems = await repository.GetAsync();
} catch (Exception ex) {
//TODO: Log error
}
}
}
}


... and have whatever is binding/using to the view model (ie the view, another model, a test, etc) load the data after initialization.

This allows the testing to be much simpler and to the point

For example

[TestClass]
public class MainVmTests {
[TestMethod]
//Arrange
var repoMock = new Mock<IRepository<ToDoItem>>();
var subject = new MainVM(repoMock.Object);

//Act

//Assert
Assert.IsNotNull(subject.ToDoItems);
}

[TestMethod]
//Arrange
var repoMock = new Mock<IRepository<ToDoItem>>();
repoMock.Setup(_ => _.GetAsync()).Throws(new AggregateException());
var subject = new MainVM(repoMock.Object);

//Act