Unit Testing That Events Are Raised in C# (In Order)

Unit testing that events are raised in C# (in order)

Everything you've done is correct, providing you want your test to ask "What is the last event that was raised?"

Your code is firing these two events, in this order

  • Property Changed (... "My Property" ...)
  • Property Changed (... "MyOtherProperty" ...)

Whether this is "correct" or not depends upon the purpose of these events.

If you want to test the number of events that gets raised, and the order they get raised in, you can easily extend your existing test:

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
List<string> receivedEvents = new List<string>();
MyClass myClass = new MyClass();

myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
receivedEvents.Add(e.PropertyName);
};

myClass.MyProperty = "testing";
Assert.AreEqual(2, receivedEvents.Count);
Assert.AreEqual("MyProperty", receivedEvents[0]);
Assert.AreEqual("MyOtherProperty", receivedEvents[1]);
}

Unit testing that an event is raised in C#, using reflection

I recently wrote a series of blog posts on unit testing event sequences for objects that publish both synchronous and asynchronous events. The posts describe a unit testing approach and framework, and provides the full source code with tests.

I describe the implementation of an "event monitor" which allows writing event sequencing unit tests to be written more cleanly i.e. getting rid of all the messy boilerplate code.

Using the event monitor described in my article, tests can be written like so:

var publisher = new AsyncEventPublisher();

Action test = () =>
{
publisher.RaiseA();
publisher.RaiseB();
publisher.RaiseC();
};

var expectedSequence = new[] { "EventA", "EventB", "EventC" };

EventMonitor.Assert(publisher, test, expectedSequence);

Or for a type that implements INotifyPropertyChanged:

var publisher = new PropertyChangedEventPublisher();

Action test = () =>
{
publisher.X = 1;
publisher.Y = 2;
};

var expectedSequence = new[] { "X", "Y" };

EventMonitor.Assert(publisher, test, expectedSequence);

And for the case in the original question:

MyClass myObject = new MyClass();
EventMonitor.Assert(myObject, () => { myObject.Width = 42; }, "Width");

The EventMonitor does all the heavy lifting and will run the test (action) and assert that events are raised in the expected sequence (expectedSequence). It also prints out nice diagnostic messages on test failure. Reflection and IL are used under the hood to get the dynamic event subscription working, but this is all nicely encapsulated, so only code like the above is required to write event tests.

There's a lot of detail in the posts describing the issues and approaches, and source code too:

http://gojisoft.com/blog/2010/04/22/event-sequence-unit-testing-part-1/

Unit testing an event

As @Scott Chamberlain said in the comments, your example code doesn't represent a real test case. A minimum test case would be something like this:

[TestClass]
public class ObservableObjectTests {
[TestMethod]
public void PropertyChangedEventHandlerIsRaised() {
// Create the object to test (sut)
var sut = new SubObservableObject();

// Create a flag to monitor if event handler has fired
// set it to false initially, since it hasn't...
bool raised = false;

// Register our test event handler, with the PropertyChanged
// event.
sut.PropertyChanged += (Sender, e) => {
// Check that when the event handler is called
// it is for the 'ChangedProperty'
Assert.IsTrue(e.PropertyName == "ChangedProperty");
// Set our flag to indicate that event was triggered
raised = true;
};

// Actually perform the test, by setting 'ChangedProperty' to
// a new value. This will fire the code above if it works.
sut.ChangedProperty = "newValue";

// Validate that our raised flag has been set to true, indicating
// that our test event handler was triggered.
Assert.AreEqual(true, raised);
}
}

Note, in order for the above to work, I've assumed a lot about the code that is being tested. Essentially, I've assumed that the code being tested looks a lot like this:

public class SubObservableObject : INotifyPropertyChanged {
public string ChangedProperty {
get { return _changedProperty; }
set {
_changedProperty = value;
PropertyChanged(this, new PropertyChangedEventArgs("ChangedProperty" ));
}
}

public string _changedProperty;

public event PropertyChangedEventHandler PropertyChanged;
};

As has been mentioned in the comments, this is a minimum example code to get the test you are asking about to work. The tutorial you are following should have additional tests to help validate their code. The following test would be enough to force the PropertyChanged event to be tested for null.

[TestMethod]
public void PropertyCanChangeWithNoEventHandlersSet() {
var sut = new SubObservableObject();

// The next line will throw a null exception with the minimal
// code written above, since there is no check for
// if(null != PropertyChanged) before invoking the PropertyChanged
// event.
sut.ChangedProperty = "newValue";

Assert.AreEqual("newValue", sut.ChangedProperty);
}

In a real code base, it's likely that this check and invocation will have been re-factored into a single function that is invoked from all properties in the class.

Depending on the version of C# being targeted, it's also possible that this method automatically detects the name of the property being changed, using CallerMemberName so that it doesn't have to be explicitly provided. This would result in code like this from microsoft.

// This method is called by the Set accessor of each property. 
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

With this method being invoked by each individual property:

public string ChangedProperty {
get { return _changedProperty; }
set {
_changedProperty = value;
NotifyPropertyChanged();
}
}

How to unit test C# events with xUnit

From this answer, this documentation and from the guidance by @ZevSpitz in comments I was able to write the below tests for Start().
Though I couldn't verify if the same code path OnSomethingHappened got executed or was it some other subscription which calls m_secondDependencyMock.DoYourJob(soAndSo).

TestedServiceTest.cs

public class TestedServiceTest
{
readonly Mock<IDependency> m_dependencyMock;
readonly Mock<ISecondDependency> m_secondDependencyMock;

ITestedService testedService;

public TestedServiceTest()
{
m_dependencyMock = new Mock<IDependency>();
m_secondDependencyMock = new Mock<ISecondDependency>();
testedService = new TestedService(m_dependencyMock.Object, m_secondDependencyMock.Object);
}

[Fact]
public async Start_DependencyStartInvoked()
{
// Arrange
m_dependencyMock.Setup(x=> x.Start()).Verifyable();

// Act
await testedService.Start();

// Assert
//This tests if the IDependecy.Start is invoked once.
m_dependencyMock.Verify(x=>x.Start(), Times.Once);
}

[Fact]
public async Start_EventListenerAttached()
{
// Arrange
m_dependencyMock.Setup(x=> x.Start()).Verifyable();
m_dependencyMock.SetupAdd(m => m.SomethingHappened += (sender, args) => { });

// Act
await testedService.Start();

// Assert
// The below together with SetupAdd above asserts if the TestedService.Start adds a new eventlistener
// for IDependency.SomethingHappened
m_dependencyMock.VerifyAdd(
m => m.SomethingHappened += It.IsAny<EventHandler<SoAndSoEventArgs>>(),
Times.Exactly(1));
}

[Fact]
public async Start_SomthingHappenedInvoked_HandlerExecuted()
{
// Arrange
m_dependencyMock.Setup(x=> x.Start()).Verifyable();
m_secondDependencyMock.Setup(x=> x.DoYourJob(It.IsAny<SoAndSo>())).Verifyable();

// Act
await testedService.Start();
// This will fire the event SomethingHappened from m_dependencyMock.
m_dependencyMock.Raise(m => m.SomethingHappened += null, new SoAndSoEventArgs());

// Assert
// Assertion to check if the handler does its job.
m_secondDependencyMock.Verify(x=> x.DoYourJob(It.IsAny<SoAndSo>()), Times.Once);
}
}

How to raise an event when unit testing asynchronous method in my case?

Since the view model depends on the IInfoLoader abstraction, it can be mocked to behave as expected when the desired member is invoked.

Review the comments in the following example

[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success() {
//Arrange
var info = new MyInfo();
List<MyInfo> expectedInfoList = new List<MyInfo>() { info };

// WHAT DO I DO HERE?
var dependency = new Mock<IInfoLoader>(); //mock the dependency

dependency
// When LoadInfoAsync is invoked
.Setup(_ => _.LoadInfoAsync())
// Use callback to raise event passing the custom arguments expected by the event delegate
.Callback(() => dependency.Raise(_ => _.InfoLoaded += null, info))
// Then allow await LoadInfoAsync to complete properly
.Returns(Task.CompletedTask);

MyViewModel subject = new MyViewModel(dependency.Object);

//Act
await subject.StartLoadInfoAsync();


//Assert
List<MyInfo> actualInfoList = subject.InfoList;

actualInfoList.Should().NotBeEmpty()
And.BeEquivalentTo(expectedInfoList); //Using FluentAssertions

}

Note how a Callback is used to capture when LoadInfoAsync is invoked by the subject so that an event can be raised by the mock, allowing the subject under test to flow to completion as desired

Reference MOQ Quickstart: Events

Unit Testing an Event Firing From a Thread

A lock is just not appropriate here, you'll want to signal an event. For example:

    public void CheckFinishedEventFiresTest() {
var threadTest = new ThreadRunner();
var finished = new ManualResetEvent(false);
threadTest.Finished += delegate(object sender, EventArgs e) {
finished.Set();
};
threadTest.StartThreadTest();
threadTest.FinishThreadTest();
Assert.IsTrue(finished.WaitOne(1000));
}


Related Topics



Leave a reply



Submit