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?