Masstransit In Memory Testing waiting for consumers to execute - c#

So I've been trying to write a test for mass transit using the in-memory feature. I wondered what peoples approach was to waiting for consumers to execute. In the example below a use a sleep or I've also tried a while loop, but not a fan of either, any better ideas? I basically want to check that the consumer is executed.
[Fact]
public async Task SomeTest()
{
var busControl = Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ReceiveEndpoint("commands", ec =>
{
ec.LoadFrom(context);
});
});
var address = new Uri(bus.Address, "commands")
await sendEndpoint.Send(MyExampleCommand());
Thread.Sleep(2000);
//Check nsubstitute mock received
}

Look at the test harness features that are built into MassTransit. They should give you some good ideas of how to test them.
You can look at the harness tests to see how they should be used. Note that they work with any test framework, not just NUnit.
https://github.com/MassTransit/MassTransit/blob/develop/tests/MassTransit.Tests/Testing/ConsumerTest_Specs.cs
The Testing documentation explains how to use the test harnesses.

Related

Unit testing and mocking

I am new to ASP.NET Core MVC and I was wondering if any one could help me with the unit testing to remove a user from the database
Controller
public async Task<ActionResult> RemoveIdAsync(string Id)
{
try
{
var result = await _udService.RemoveId(Id);
return Ok(result);
}
catch (ServiceException)
{
return _internalServerErrorStatusCode;
}
}
The test should return asynt Task since the subject under test is also async
Setup the mocked member to return from an async call by using ReturnsAsync
The subject under test makes no use of User class, so it is not really needed for the test
public async Task RemoveIdAsyncTest() {
//Arrange
_mockudService //...assuming Mock<IUdService>
.Setup(_ => _.RemoveId(It.IsAny<string>()))
.ReturnsAsync(true);
var removeController = new RemoveController(_mockudService.Object);
var id = "...";
//Act
var result = await removeController.RemoveIdAsync(id); //will return OkObjectResult
//Assert
OkObjectResult actual = result as OkObjectResult;
Assert.IsNotNull(actual);
Assert.IsTrue((bool)actual.Value);
// ... assert expected behavior
}
It is great to see you are starting to write Unit Tests.
An example is provided in the previous answer so I will not repeat that but I will stress in learning more about unit tests.
Unit Test
A test that verifies the behavior of some small part of the overall system.
What makes a test a unit test is that the System Under Test (SUT) is a very small subset of the overall system and may be unrecognizable to someone who is not involved in building the software. The actual SUT may be as small as a single object or method that is a consequence of one or more design decisions although its behavior may also be traced back to some aspect of the functional requirements. There is no need for unit tests to be readable, recognizable or verifiable by the customer or business domain expert.
A test is NOT a unit test if:
It talks to the database.
It communicates across the network.
It touches the file system.
It can’t run correctly at the same time as any of your other unit tests.
You have to do special things to your environment (such as editing config files) to run it.
Unit tests encourage good design and rapid feedback and they seem to help teams avoid a lot of trouble.
More info: https://codeanit.medium.com/developers-guide-write-good-test-5e3e3cdec78e
Furthermore, as we are using MVC framework, the rule of thumb, in MVC is Slim Controller, Fat Model. Having said that, you can use Repository Model for your database activities, and move your business logics to a separate classes.
Clean Code, SOLID Design Principals and following Clean Architecture would also be of some value. https://blog.ndepend.com/clean-architecture-example-part-one
And wish you all the very best!
Cheers,

Unit Testing MassTransit Consumer With XUnit

My team is just getting started with using MassTransit and we are trying to figure out how unit testing IConsumer implementations work. The MassTransit documentation is incomplete and all of the examples I have found so far use NUnit. We are trying to use XUnit with Moq to do our unit testing.
I know that we need to set up one instance of the MassTransit test harness, which in NUnit is done with a OneTimeSetup and to replicate that we should use IClassFixture in XUnit. I'm struggling with getting that to work with the test harness, though.
I have seen Chris Patterson's ConsumerTest_Specs.cs example on the MassTransit GitHub, but I'm having a hard time translating it to work in XUnit and Moq.
https://github.com/MassTransit/MassTransit/blob/master/src/MassTransit.Tests/Testing/ConsumerTest_Specs.cs
I'm trying to test a very simple consumer to start with. All it does is receive the message and then make a call to a repository. I want to write an XUnit test that mocks the repository and verifies that the repository method was called.
Does anyone have any examples of how to do something like this?
public class NewVMRequestRejectedConsumer : IConsumer<INewVMRequestRejected>
{
private readonly INewVMRequestRepository _newVMRequestRepository;
public NewVMRequestRejectedConsumer(INewVMRequestRepository newVMRequestRepository)
{
_newVMRequestRepository = newVMRequestRepository;
}
public Task Consume(ConsumeContext<INewVMRequestRejected> context)
{
_newVMRequestRepository.AddReasonForRejection(context.Message.RequestId, context.Message.Reason);
return Task.CompletedTask;
}
}
Since ConsumeContext<out T> and INewVMRequestRepository are interfaces there is no problem mocking them using moq, e.g.
//Arrange
var repository = new Mock<INewVMRequestRepository>();
var sut = new NewVMRequestRejectedConsumer(repository.Object);
//Act
sut.Consume(Mock.Of<ConsumeContext<INewVMRequestRejected>>(m =>
m.Message.RequestId == "id" && m.Message.Reason == "reason"));
//Assert
repository.Verify(m => m.AddReasonForRejection("id", "reason"), Times.Once);

How do I verify if something didn't happen?

We are using OpenCover for our solution test coverage and I noticed that
public async Task Build(ProcessorContext context)
{
context.ResultBetSlip.Bets.Clear();
// Here OpenCover tells me that I need to cover two branches
// so I assume I need to verify that GetAvailablePlugins can be empty and
// no Build method was called.
// How do I do that?
foreach (var plugin in _pluginFactory.GetAvailablePlugins())
{
await plugin.Build(context);
}
}
Now my test would look like that
[Test]
public async Task Build_ShouldntEnterForeachWhenThereAreNoPluginsRegistered()
{
// Arrange
var pluginFactoryMock = new Mock<IBetSlipProcessorServicePluginFactory>();
var sut = new BetSlipProcessorService(pluginFactoryMock.Object);
pluginFactoryMock
.Setup(pf => pf.GetAvailablePlugins())
.Returns(new List<IBetSlipProcessorServicePlugin>());
// Act
await sut.Build(AutoFixtureSimplified.Create<ProcessorContext>());
// Assert
???
}
Should I even consider testing such case if it is possible?
EDIT:
As requested this is the test coverage report:
And here you can find gist of all the tests that I do in order to achieve such coverage.
https://gist.github.com/kuskmen/df3f112b2b6d880741ee6ab559d64d53
I am assuming you are using the Moq framework for mocking. If this is the case you can do one of two things.
You can create your mock in strict mode
You can expect that when the plugin.Build(..) method is called that an exception is thrown.
A similar question was asked here: How to verify that method was NOT called in Moq?
edit:
I simulated the exact scenario that you are seeing and I have narrowed it down to the data type that you are iterating over. Due to the fact that you are using a list I would guess there is some internal workings of the list that are causing this problem. I changed all the list references to arrays and the branch coverage returned as expected.

MassTransit consumer hard to test

I am having 2 issues testing MassTransit consumers:
Sync issue
MessageData
The first one is like this:
var testConsumer = TestFactory.ForConsumer<ImageUploadConsumer>().New(
test =>
{
test.UseConsumerFactory(new InstanceConsumerFactory<ImageUploadConsumer>(ImageConsumer));
test.Publish(message, (scenario, context) =>
{
});
});
testConsumer.Execute(); //Is non blocking
The following line (below) fails, because this line:
moqFileMetaRepo.Verify(_ => _.Add(It.IsAny<IFileMeta>()),Times.Once );
is executed 9.9/10 before... this line ever did:
public async Task Consume(ConsumeContext<ImageUploadWithThumb> context)
My fix has been to do
moqFileMetaRepo
.Setup(repo => repo.Add(It.IsAny<IFileMeta>()))
.Callback(() => { AutoEvent.Set(); });
And call the following before the assert:
AutoEvent.WaitOne(TimeSpan.FromSeconds(10));
Which is really a lot of work. And makes TDD or Testing in general a hassle, which I fear is only going to get ignored over time.
MessageData issue is another one. Here's the payload I'm sending through
message = new ImageUploadWithThumb()
{
Id = Guid.NewGuid(),
FileName = "Test.jpg",
User = "Me",
Extension = "jpg",
OriginalImage = new ConstantMessageData<byte[]>(new Uri("https://g00gle.com"), new byte[] { 1, 2, 3 })
};
I'm expecting to get byte[] { 1, 2, 3 } on the other end without having to resort to creating an actual persistence.
Instead:
On the sender side the MessageData.Value resolves ok. The consumer totally bombs. Works in prod though =_= which is not where testing should be.
I really just want to mock and UnitTest my consumer w/o having to wrestle with the framework - preferably in under 5 mins or so. Is there a way out while sticking to MT3?
I would suggest looking at the MassTransit.TestFramework package. It does require NUnit, but you could always take the classes and port it to your own test framework.
All of the MassTransit unit tests are written using the fixtures in this framework. The original .Testing namespace is in a world of hurt right not, it didn't survive completely and I'm unsure it's actually working completely. It wasn't designed for async, so it was difficult to transition without trashing it entirely.

Unit Test Garbage Collection

Question
Do unit tests automatically dispose resources via garbage collection (System.IO.Stream in my case) once the test(s) have completed, or are things left open/in-use, requiring the disposing of IDisposable objects?
Context / Information
I'm currently making a unit test for a file uploader which uses a System.IO.Stream.
I've Moq'd out the HttpPostedFileBase with the InputStream of the file powered by a System.IO.MemoryStream, which all works as expected.
I currently have (altered for brevity):
[TestMethod]
public void TestUpload()
{
var stream = FunctionCreatingTheMemoryStream();
try
{
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
finally
{
stream.Dispose();
}
}
The question is with the MemoryStream instance that is created:
var stream = new FunctionCreatingTheMemoryStream();
Is it worthwhile placing any code after this in a try catch and then disposing of the stream in the finally statement, or with it being a unit test, will the memory stream be disposed of automatically?
So is it necessary to do this, or could it simply just be:
[TestMethod]
public void TestUpload()
{
var stream = FunctionCreatingTheMemoryStream();
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
The answer ultimately depends on the unit testing framework you use, but in .NET, none of the three major test frameworks (MSTest, NUnit, xUnit.net) automatically dispose of things. You have to manually ask them to do so.
You could argue that when executing a test suite, the test runner in principle launches a new process, runs all the tests, and then the process exits.
For some implementations of IDisposable, like MemoryStream, that simply means that the memory is reclaimed when the process exits. However, you can't always rely on that, because some disposable types may access out-of-process resources. You could theoretically have objects holding on to memory-mapped-files, named pipes, SQL Server connections, etc. Even if the test process exits, you may leave behind such resources. They'll probably time out sooner or later (like SQL Server connections returning to the pool), but it may slow down your system.
Furthermore, some test runners are attempting very hard to be clever these days, so they reuse one or more processes to be able to run faster, changing your test suite in and out of AppDomains.
So, in the end, unless you have something like a MemoryStream, where you're absolutely certain that it's not a big deal to leave it behind, you should deterministically dispose of your objects in your tests.
However, if you're doing Test-Driven Development, you should adopt the GOOS attitude of listening to your tests. If you write a lot of tests that involve IDisposable objects, you should consider if you can simplify your SUT's API. It depends on what you're doing, but if you write mostly managed code, you shouldn't need IDisposable much, because it's a Leaky Abstraction that leaks that the SUT depends on unmanaged resources..
In the past I have written a "Dustcart" class that implements IDisposable, and contains a collection of objects to dispose. These are disposed in the opersite order to how they are added (use a stack to implement it).
Then the test code looks like.
[Setup]
Public void Setup()
{
_dustcart = new Dustcart()
}
[TearDown]
public void TearDown ()
{
_dustcart.Dispose();
}
[TestMethod]
public void TestUpload()
{
var stream = _dustcart.DisposeOnTearDown(FunctionCreatingTheMemoryStream());
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
DisposeOnTearDown() is a generic method. You could put this this in a super class that all your tests inherent from, that also includes object mothers for the classes you need to mock etc.
However if you are not very careful your test code becomes harder to understand with no real benefit to the quality of the software you are testing. The tests are there to do a job and they have to be no better than is needed to do that job.
Totally agree with everyone that you need to dispose such objects. You can simplify your code a bit by using "using" statements, like this:
[TestMethod]
public void TestUpload()
{
using (var stream = FunctionCreatingTheMemoryStream())
{
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
}

Categories

Resources