How to unit test C# events with xUnit - c#

I want to unit test if an event raised by a dependency being subscribed by a class under test.
To set the context, I have the below interfaces and classes.
ITestedService.cs
public interface ITestedService
{
Task Start();
Task Stop();
}
IDependency.cs
public interface IDependency
{
event EventHandler<SoAndSoEventArgs> SomethingHappened;
Task Start();
Task Stop();
}
ISecondDependency
public interface ISecondDependency
{
Task DoYourJob(SoAndSo soAndSo);
}
TestedService.cs
public class TestedService : ITestedService
{
readonly IDependency m_dependency;
readonly ISecondDependency m_secondDependency;
public TestedService(
IDependency dependency,
ISecondDependency secondDependency)
{
m_dependency = dependency;
m_secondDependency = secondDependency;
}
public async Task Start()
{
m_dependency.SomethingHappened += OnSomethingHanppened;
await m_dependency.Start();
}
private async void OnSomethingHanppened(object sender, SoAndSoEventArgs args)
{
SoAndSo soAndSo = SoAndSoMapper.MapToDTO(args);
await m_secondDependency.DoYourJob(soAndSo),
}
}
With the above context, I want to Unit test Start() method of the TestedService class using xUnit.
I want to know how I can:
Assert if the event is attached to a handler.
Simulate the event IDependency.SomethingHappened being fired.
Verify if the OnSomethingHappened method is executed
Verify if the ISecondDependency.DoYourJob(soAndSo) is called.

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);
}
}

The purpose of unit testing can be:
Verify logic results in the output you want
Verify crucial calls are made (I would only do if I want to make sure another developer does not remove a piece of code by mistake but in general verifying
whether some call is made is not necessary and even worse, makes
unnecessary maintainability work)
Having said that, you do not need to test the internals of the language. For example in this case you do not need to verify that when you register an event, that the method registered will be called. It is the job of the language to do that. That is tested by the language.
So you verified that the Start method does the calls that you expected. This by the way, as I mentioned above, only makes sense to do if there is a reason to do so such as purpose number 2 above.
Now you know the OnSomethingHappened is going to be triggered. The language guarantees that.
What you want to test is the actual implementation within OnSomethingHappened. For this, you need to make this method more testable by making it reachable (access modifier private is not going to work) and by making it's dependencies also mockable (SoAndSoMapper is not mockable).
Note: Unit testing is more of an activity of making code testable rather than the activity of figuring out how to write the test. If writing the test is difficult, that can be a sign that code is not easily testable.
public class TestedService
{
readonly IDependency m_dependency;
readonly ISomethingDoer m_somethingDoer;
public TestedService(
IDependency dependency,
ISomethingDoer somethingDoer)
{
m_dependency = dependency;
m_somethingDoer = somethingDoer;
}
public async Task Start()
{
m_dependency.SomethingHappened += m_somethingDoer.OnSomethingHanppened;
await m_dependency.Start();
}
}
interface ISomethingDoer
{
Task OnSomethingHanppened(object sender, SoAndSoEventArgs args);
}
class SomethingDoer : ISomethingDoer
{
readonly ISecondDependency m_secondDependency;
readonly ISoAndSoMapper m_soAndSoMapper;
public SomethingDoer(ISecondDependency secondDependency, ISoAndSoMapper soAndSoMapper)
{
m_secondDependency = secondDependency;
m_soAndSoMapper = soAndSoMapper;
}
public async Task OnSomethingHanppened(object sender, SoAndSoEventArgs args)
{
SoAndSo soAndSo = m_soAndSoMapper.MapToDTO(args);
await m_secondDependency.DoYourJob(soAndSo),
}
}
Now you can test what OnSomethingHappened does by creating a test class for SomethingDoer, mocking it's dependencies and verifying for example that given soAndSoMapper mock returns some value, the secondDependency is called with that value. Although once again, OnSomethingHappened doesn't do much. Therefore it is arguable whether you want to test this.

Related

How to unit test MediatR method that returns Unit.Value

How do you unit test a MediatR method returning Unit.Value?
I never understood what Unit.Value stands for, either, in MediatR.
Does it mean it returns false in case of error and true in every other instance? So in this case a way to unit test would be to make sure no errors (mock dependencies etc), and just check if result in the shape of Unit.Value equals true?
Thanks.
Unit is a type with a single value. You can think of it as void, except is a regular type and not a keyword.
You should test the method like any method that returns void: Verify that it has the desired side effects.
You can think of Unit as void - returns nothing.
(Note: newer versions of Mediatr wrap this up so you can just return Task)
But for example purposes, suppose you have a Handler like this
public class MyHandler : IRequestHandler<Unit>
{
public MyHandler(IDoSomething doSomething)
{
_doSomething = doSomething;
}
public Task Handle(MyRequest req, CancellationToken cancellationToken)
{
_doSomething.Do();
return Unit.Value;
}
}
Your tests can mock your dependency, and assert it was called:
public class MyHandlerTests
{
private Mock<IDoSomething> _doSomethingMock;
[SetUp]
public void SetUp()
{
_doSomethingMock = new Mock<IDoSomething>();
}
[Test]
public async Task Calls_DoSomething()
{
// Arrange
var handler = new MyHandler(_doSomethingMock.Object);
// Act
await handler.Handle(new MyRequest(), CancellationToken.None);
// Assert
_doSomethingMock.Verify(x => x.Do(), Times.Once);
}
}
you can use auto-fixture for mocking and generating Data,I hope use it and enjoying with write automate test

How to await an async Command for unit testing?

I'm trying to unit test a command but because its an async command, the test method goes into the assertions before the command is finished. I have looked up solutions to this problem and they all talk about creating an AsyncCommand interface etc which I don't want to do as I only need to await the commands for the unit tests purposes. So is there another solution to this which is simpler and doesn't require creating another interface etc?
this is my Command class:
public class Command : ICommand
{
public void Execute(object parameter)
{
//exeute...
}
//other stuff....
}
Thats the tested class:
pubic class MyClass
{
private Command commandForTest;
public Command CommandForTest
{
get
{
if (commandForTest == null)
{
commandForTest = new Command(async (o) =>
{
if(someCondition)
await SomeMethod();
else
await AnotheMrthod();
});
}
return commandForTest;
}
}
}
This is the test Method:
[TestMethod]
public async Task Test()
{
MyClass myclass = new MyClass();
await Task.Run( () => myclass.CommandForTest.Execute());
//Assert....
}
So is there another solution to this which is simpler and doesn't require creating another interface etc?
No and yes. There is another solution. It is not simpler. The simplest and most straightforward solution is to use an IAsyncCommand interface. Or an AsyncCommand implementation that your unit test can cast the ICommand to (more brittle).
But if you want to go the hard way, then yes, you can technically detect when an async void method completes. You do this by writing your own SynchronizationContext and listening to OperationStarted and OperationCompleted. You'll also need to build a queue of work and write a main loop that processes the queue.
I have a type that does this. It is called AsyncContext and it is part of AsyncEx. Usage:
[TestMethod]
public void Test() // note: not async
{
MyClass myclass = new MyClass();
AsyncContext.Run(() =>
{
myclass.CommandForTest.Execute();
});
//Assert....
}
Again, I strongly recommend using IAsyncCommand. The real problem is that the core MVVM types are insufficient. So most people use IAsyncCommand or MvxAsyncCommand or AsyncCommand or expose the command logic as an async Task method on the VM.

Avoiding thread.sleep in code while unit testing with Moq

I have methods which have multiple thread.sleep which last for 20 seconds at times. This is a business requirement. I am trying to unit test these methods, by mocking and skipping these sleeps so that tests can run faster and doesn't actually wait for 20 seconds. Using the moq framework.
Appreciate any ideas on how to implement this.
There is probably no way to mock Thread.Sleep because it's a static method and those cannot be mocked with DynamicProxy based mocking Frameworks like moq.
One option would be to use Profiler API based tools like Microsoft Fakes (only in VS Enterprise) or Typemoq professional.
The better option is not to call Thread.Sleep directly in your business logic. What you can do instead is to introduce an Interface like this
public interface ISleepService
{
void Sleep(int ms);
}
Then create a default implementation that you use in your code:
public class SleepService: ISleepService
{
public void Sleep(int ms)
{
Thread.Sleep(ms);
}
}
Add a dependency of ISleepService to your Business Logic
public class MyBusinessLogic()
{
private ISleepService _sleepService;
public MyBusinessLogic(ISleepService sleepService)
{
_sleepService = sleepSerivce;
}
public void MyBusinessMethod()
{
// your code
_sleeService.Sleep(20000);
// more code
}
}
You can then easily mock the ISleepService in your unit tests and pass the real implementation in your production code
You can actually introduce interface for Thread.sleep methods and this you can mock while writing UTs
public interface IThreadSleep
{
void Sleep(int milliSec);
}
You can have implementation , something like this
public class ThreadSleep : IThreadSleep
{
public void Sleep(int milliSec)
{
Thread.Sleep(milliSec);
}
}
In your business class, just inject this interface and you can then mock Thread.sleep
public class Class1
{
IThreadSleep _threadSleep;
public Class1(IThreadSleep threadSleep)
{
_threadSleep = threadSleep;
}
public void SomeMethod()
{
//
_threadSleep.Sleep(100);
}
}
Hope this helps.
Don't know actual code you have but at least to have some idea. You could wrap your Thread.Sleep into the interface and then inject that one to your business handler\controller. In the actual implementation use Thread.Sleepto actually wait but within the tests mock that interface to avoid Thread.Sleep. For example:
public interface IMySleepContext
{
void Sleep(int milliseconds);
}
public class MySleepContext : IMySleepContext
{
public void Sleep(int milliseconds)
{
Thread.Sleep(milliseconds);
}
}
public class MyController
{
private readonly IMySleepContext _mySleepContext;
public MyController(IMySleepContext mySleepContext)
{
_mySleepContext = mySleepContext;
}
public void MyMethod()
{
//do something
_mySleepContext.Sleep(20000);
//do somethign
}
}
Tests:
//Arrange
MyController mc = new MyController(Mock.Of<IMySleepContext>());
//Act
mc.MyMethod();
//Assert
//do assert

How do i write a failing test to add another branch in an if statement without external state

With this code:
Public class Processor {
Public Processor(Ifoo colloborator, Ibar otherCollobotator)
Public void Process() {
// if (newFoo)
// new action
If (foo)
this.colloborator.doSomething();
If (bar)
this.colloborator.doSomethingElse();
Else this.otherColloborator.doSomethingCompletelyDiffetent();
}
I want to add a another branch at the top to do something else (commented out). I know one way to do it, it involves verifying, or not, calls on colloborators using an appropriate mock/spy.
And to be clear I have done this already, succesfully and with TDD 'without' introducing another colloborator.
How would you tackle this? From a test first perspective?
I think eventually it could be refactored with something called pluggable object/adapter.
Assuming your new action also calls the collaborator, you can mock it out.
Example with RhinoMocks:
[TestMethod]
public void Test()
{
//Arrange
ICollaborator mock = MockRepository.GenerateMock<ICollaborator>();
Processor myProc = new Processor(mock, ...);
//Act
myProc.Process();
//Assert
mock.AssertWasCalled(x => x.MethodToBeCalled);
}
This will of course fail if you do not change your Process method.
Just like you said, you'd need to check that when condition is true, new action is called, and when condition is false, then new action is not called. So, first we'd define our new interface:
public interface INewAction
{
void NewAction();
}
Then, we modify our processor (note that we DID NOT yet add the new if branch):
public class Processor {
private readonly INewAction _newAction;
public Processor(Ifoo colloborator, Ibar otherCollobotator, INewAction newAction)
{
// whatever we had before
_newAction = newAction;
}
public void Process() {
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
Now we write our test cases:
[TestClass]
public class ProcessorTests
{
[TestMethod]
public void Process_GivenNewFoo_CallsNewAction()
{
// arrange 'newfoo' condition
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Once);
}
[TestMethod]
public void Process_GivenNewFoo_False_DoesNotCallNewAction()
{
// arrange 'newfoo' condition to be false
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Never);
}
}
When we run them, the second test will pass -> well, this is expected, because essentially the behaviour is if NOT newfoo then don't call it. But the first test WILL fails (as is the TDD approach).
And now we modify the Processor again, just the Process() method:
public void Process() {
if(newFoo)
{
_newAction.NewAction();
}
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
At this point both the tests pass and we completed the TDD cycle.

Assert that a method is called to bring an if condition under test

Here is an example where I am testing the line if (true). But although the condition is obviously true, Moq tells me the method was never called.
public class test
{
public virtual void start()
{
if (true)
called();
}
public virtual void called()
{
}
}
[Test]
public void QuickTest()
{
var mock = new Mock<test>();
mock.Object.start();
mock.Verify(t => t.start(), "this works");
mock.Verify(t => t.called(), "crash here: why not called?");
}
How do I test that the method call to called() has happened?
I thought Moq was the solution, but from the comments it looks like it isn't so I've made another example without any reference to Moq:
public class test
{
public bool condition = true;
public test(bool cond)
{
condition = cond;
}
public virtual string start()
{
var str = "somestuff";
if (condition)
str += called();
str += "something more";
return str;
}
public virtual string called()
{
return "something more";
}
}
[Test]
public void ConditionTrue_CallsCalled()
{
var t = new test(true);
t.start();
//syntax? t.HasCalled("called");
Assert.IsTrue(result.Contains("something more"));
}
[Test]
public void ConditionFalse_NoCall()
{
var t = new test(false);
t.start();
//syntax? t.HasNotCalled("called");
// Can't check this way because something more is already being added
Assert.IsFalse(result.Contains("something more"));
}
Is it possible to do this? Is it worthwhile?
Regarding the first piece of code:
mock is a mock object. That means all the methods are overridden and do nothing. So it's entirely normal that calling mock.start() doesn't do anything and called() is never called.
If you want to mock just called() and use the real implementation of start(), you need to do partial mocking.
But I would advise against that, I would even advise against trying to test just this class. You will couple your test code too tightly to your implementation code. Think about doing TDD: ask yourself what feature of your application breaks if that if test is not there. Write a test against that feature, which should fail. Then write the if test to fix the test.

Categories