I have implemented the MVP (MVC) pattern in c# winforms.
My View and Presenter are as follows (without all the MVP glue):
public interface IExampleView { event EventHandler<EventArgs> SaveClicked; string Message {get; set; } } public partial class ExampleView : Form { public event EventHandler<EventArgs> SaveClicked; string Message { get { return txtMessage.Text; } set { txtMessage.Text = value; } } private void btnSave_Click(object sender, EventArgs e) { if (SaveClicked != null) SaveClicked.Invoke(sender, e); } } public class ExamplePresenter { public void OnLoad() { View.SaveClicked += View_SaveClicked; } private async void View_SaveClicked(object sender, EventArgs e) { await Task.Run(() => { // Do save }); View.Message = "Saved!" } I am using MSTest for unit testing, along with NSubstitute for mocking. I want to simulate a button click in the view to test the controller's View_SaveClicked code as have the following:
[TestMethod] public void WhenSaveButtonClicked_ThenSaveMessageShouldBeShown() { // Arrange // Act View.SaveClicked += Raise.EventWith(new object(), new EventArgs()); // Assert Assert.AreEqual("Saved!", View.Message); } I am able to raise the View.SaveClicked successfully using NSubstitute's Raise.EventWith. However, the problem is that code immediately proceeds to the Assert before the Presenter has had time to save the message and the Assert fails.
I understand why this is happening and have managed to get around it by adding a Thread.Sleep(500) before the Assert, but this is less than ideal. I could also update my view to call a presenter.Save() method instead, but I would like the View to be Presenter agnostic as much as possible.
So would like to know I can improve the unit test to either wait for the async View_SaveClicked to finish or change the View/Presenter code to allow them to be unit tested easier in this situation.
Any ideas?