I'm using MassTransit to exchange messages between two microservices, and I have a consumer that publishes an event when it receives a command message.
While adding a unit test to cover this message exchange I've noticed that when no event is posted the test takes about 30s to finish, which I assume is a default timeout. Here's the xUnit unit test that reproduces the problem.
using System;
using Xunit;
using MassTransit;
using MassTransit.Testing;
using System.Linq;
using SomeProject.MassTransitInterface;
namespace SomeProject.MassTransitInterface.Tests
{
public class CommandTests
{
[Fact]
public void Test1 ()
{
var harness = new InMemoryTestHarness();
var consumer = harness.Consumer<SomeCommandConsumer>();
harness.Start().Wait();
var command = new SomeCommand();
harness.InputQueueSendEndpoint.Send(command);
Assert.True( harness.Sent.Select<SomeCommand>().Any() );
harness.Stop().Wait();
}
}
}
Does anyone know if it's possible to tweak the timeout so that the test can fail after a couple of seconds?
You can set the TestTimeout property on the harness, which is used by all created test components.
/// <summary>
/// Timeout for the test, used for any delay timers
/// </summary>
public TimeSpan TestTimeout { get; set; }
You should set it early, like in your test constructor, so that any token or timers set use the value.
https://github.com/MassTransit/MassTransit/blob/develop/src/MassTransit/Testing/AsyncTestHarness.cs#L30
Related
I have a background task initiated in .net core 2.0 startup, inherits from backgroundservice, implementing StartAsync, StopAsync and ExecuteAsync. This task is to update some data in database table periodically based on some business logic.
While I can run the backgroundtask as an application and test using logs, db check and with the help of other tools, can the unit-testing is necessary for testing the backgroundtask? If so how to register the task as a service with dependencies and trigger the start and stop methods to assert the actual vs expected? Appreciate some basic sample unit-test method on testing timer based .net core ihostedservice backgroundtask.
Here is my basic test start just for sample, but not completed yet. Having said that, this is just a thought but not the exact working test. Here is what need some help from the community. Can also add some more asserts i.e. Assert.Verify()?
[Fact]
public async void Run_background_task_success()
{
//Arrange
IServiceCollection services = new ServiceCollection();
services.AddHostedService<BackgroundManagerTask>();
var serviceProvider = services.BuildServiceProvider();
var service = serviceProvider.GetService<IHostedService>() as BackgroundManagerTask;
var isExecuted = false;
if(await service.StartAsync(CancellationToken.None))
{
isExecuted = true;
}
await Task.Delay(10000);
Assert.True(isExecuted);
await service.StopAsync(CancellationToken.None);
}
Here's how I usually do it. You mention you are going to the database to update some data, so I'm assuming you are expecting that as a dependency from BackgroundManager
[Fact]
public void BackgroundManagerUpdatingDataTest()
{
// Arrange
Mock<IDataAccess> dbMock = new Mock<IDataAccess>();
dbMock.Setup(x => x.UpdateSomethingInDB(It.IsAny<BusinessObject>())).Returns(1); // One row updated from the DML in UpdateSomethingInDB from the BusinessObject
BackgroundManager sut = new BackgroundManager(dbMock.Object); // System under test.
// Act
await sut.StartAsync(CancellationToken.None);
await Task.Delay(500); // Give the test some time to execute.
await sut.StopAsync(CancellationToken.None); // Stop the Background Service.
// Assert
dbMock.Verify(x => x.UpdateSomethingInDB(It.IsAny<BusinessObject>()), Times.Exactly(1));
}
Above, we are plainly testing the update to the database occurred by Mocking the data access call and verifying that it was called exactly once.
You could of course Mock any other dependency out using Moq and Assert on anything else you want to verify.
I am trying to write an integration test for JMS service which looks like something like this.
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(Email message) throws InterruptedException {
try {
sendEmail(message);
}catch (Exception e){
LOGGER.log(Level.SEVERE,"Failed to deliver email",e);
Thread.sleep(TimeUnit.SECONDS.toSeconds(Optional.of(retryInterval).orElse(5)));
throw e;
}
}
private void sendEmail(Email message){
...............
}
First of all, can I mock this some how? I tried mocking it, but when I send a message the spring boot application is calling the actual JMS bean not the mock one. Seems like this is not possible.
Even if this is not possible, can I at least aoutowire the bean and somehow check if the receiveMessage method is being invoked. Furthermore, if it is being invoked, the sendEmail part should be faked so that it does not do any work. I have a few ideas such as creating a subclass for testing, but not happy with either of them. So wanted to if you can suggest me a better work around?
One approach is to use different profiles for say development, integration test and production and annotate the different components and your integration test class accordingly.
#Component
#Profile("it")
public class MessageReceiverIT {
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(SimpleMessage email) {
log.info("Integration test pretend to receive {}", email);
// (...)
This is the Integration test that uses the same Application class as the real Application, but if a message is received the MessageReceiverIT.receiveMessage() method will be invoked instead of the production component:
#RunWith(SpringRunner.class)
#SpringBootTest(classes=Application.class)
#ActiveProfiles("it")
public class JmsIntegrationTest {
#Inject
ConfigurableApplicationContext context;
#Test
public void testSend() throws Exception{
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
jmsTemplate.convertAndSend("mailbox", new SimpleMessage("it", "we need more IT"));
// (...)
Also check out Spring Boot Testing for alternative approaches such as the use of #TestConfiguration. I'm using Spring Boot in my examples, but there should be similar approaches if you have a none Spring Boot Application.
I have an Actor and when it recieves a StartMessage, it should change state using Become(Started). How do I unit test whether or not the Actor's state has changed to Started() ?
MyActor class
public class MyActor : ReceiveActor
{
public MyActor()
{
Receive<StartMessage>(s => {
Become(Started); // This is what I want to unit test
});
}
private void Started()
{
Console.WriteLine("Woo hoo! I'm started!");
}
}
Unit Test
[TestMethod]
public void My_actor_changes_state_to_started()
{
// Arrange
var actor = ActorOfAsTestActorRef<MyActor>(Props.Create(() => new MyActor()));
// Act
actor.Tell(new StartMessage());
// Assert
var actorsCurrentState = actor.UnderlyingActor.STATE; // <-- This doesn't work
Assert.AreEqual(Started, actorsCurrentState);
}
UPDATE
Related to the answer from tomliversidge: My reason for writing this unit test was academic but in reality, it's not a good unit test which is why you aren't able to do it as I'd hoped. From Petabridge's Unit Testing Guide:
In reality, if one actor wants to know the internal state of another actor then it must send that actor a message. I recommend you follow the same pattern in your tests and don’t abuse the TestActorRef. Stick to the messaging model in your tests that you actually use in your application.
You would normal test this by message passing. For example, what messages do you process in the Started state? I'm presuming your example has been simplified to the Console.WriteLine action inside of Started.
If you send the StartMessage and then a second message that is processed when in the Started state you can then assert on a response to this second message.
As a simple suggestion:
private void Started()
{
Receive<StartMessage>(msg => {
Sender.Tell(new AlreadyStarted());
}
}
if StartMessage is received whilst in the Started state, you can then assert on receiving an AlreadyStarted message.
For more info check out the Petabridge article https://petabridge.com/blog/how-to-unit-test-akkadotnet-actors-akka-testkit/
What is the correct way to write a unit test for a synchronous method calling async methods.
Right now my unit test are passing, but when I try to open the page, it never returns.
Why isn't my unit test failing? How can I make it fail?
I replicated my problem with this simple code:
My passing test:
[TestMethod]
public void DoSomeWork_WhenWeDoSomeWork_ShouldReturnDone()
{
var service = new SyncService();
const string expected = "Done";
var actual = service.DoSomeWork();
Assert.AreEqual(expected, actual);
}
My view that never returns:
public ActionResult Index()
{
var syncService = new SyncService();
return View((object)syncService.DoSomeWork());
}
My service that never returns to view:
public class SyncService
{
public string DoSomeWork()
{
return SomeWork().GetAwaiter().GetResult();
}
private async Task<string> SomeWork()
{
var task1 = Task.Delay(1000);
var task2 = Task.Delay(1000);
await Task.WhenAll(task1, task2);
return "Done";
}
}
I don't think I can help you with this specific example, but I think a good general strategy is to write two tests. One to test if the synchronous method passes the correct data and an other to test if the asynchronous method works properly.
I mostly work in JavaScript and that general approach works for me. Also you can check the documentation of your testing frameworks, maybe it provides some methods for this.
First, don't block on async code (link to my blog). By blocking on async code, you're actually causing a deadlock. This deadlock does not happen in your unit test because unit tests run in a thread pool context, not an ASP.NET context (link to my blog).
There are good reasons for not having synchronous wrappers for asynchronous methods. So I recommend getting rid of DoSomeWork completely, leaving only SomeWork (renamed to SomeWorkAsync).
To solve your problem, you should use asynchronous controller actions.
I need some advice on how to use Moq in a unit test to make sure that my class under test is behaving how I want. That is the class under test publishes an Event Aggregator (from Prism) event and I need some way of asserting that this event has been raised in my test.
I don't have a lot of resource at work and am finding it difficult to know how to set this up.
I have :-
public SomeEvent : CompositePresentationEvent<SomeEvent>
{
EventPayload
}
public SomeClass
{
void Allocate(){EventAggregator.Publish<SomeEvent>}
}
public SomeService : IService
{
SomeService(){ EventAggregator.Subscribe<SomeEvent>(DoSomething)}
void DoSomething(SomeEvent evt){}
}
I think that if my test is for SomeClass I need to verify that if I call SomeClass.Allocate a SomeEvent message is being published. How is this done?
Do I also need to verify that a mocked SomeService is receiving the SomeEvent? Or is that a seperate unit test that belongs to SomeService unit test and not SomeClass?
In any event, not sure how to set any of this up so any advice would be appreciated.
You would supply SomeClass with an IEventAggregator, which will allow you to supply a mock during testing:
public SomeClass(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
Then your test would look something like this:
var fakeEventAggregator = new Mock<IEventAggregator>();
var fakeEvent = new Mock<SomeEvent>();
fakeEventAggregator.
Setup(x => x.GetEvent<SomeEvent>()).
Returns(fakeEvent.Object);
var test = new SomeClass(fakeEventAggregator.Object);
test.Allocate();
fakeEvent.Verify(x => x.Publish(It.IsAny<SomeEventArgs>()));
If these are unit tests then you would test the subscription entirely separately in the SomeService tests. You are testing that SomeClass correctly publishes an event and that SomeService behaves correctly when it is given an event to process.