Azure service bus consumer tests - testing

I'm currently working on a net core 7 c#, service that consume a azure service bus queue using masstransit.
The thing is the consumer is working as expected, but now I've to create a Nunit test and Idk hot to write a test like that.
My consumer is waiting for an azure service bus. So when the queue receives one message, this consumer get fired and receive the "dataset downloaded" message in it's "consume method".
Idk how to test this using mocks. It's my first time making a test for a method that is called by an app that is outside of my solution... So how should I raise the event... ?
We are using Nunit. Nsubstitute for mocks and nfluent
code
Create a test with Nunit nsubstitute and nfluent for a worker consumer that is waiting to be called by a azure service bus with masstransit, when the queue receives a message.

You can test your consumer using the test harness, which provides an in-memory transport for testing your consumer. This is explained in the documentation.

One approach you could take to testing your MassTransit consumer is to use a test harness provided by MassTransit, such as InMemoryTestHarness. This harness allows you to send messages to your consumer and make assertions about how it handles those messages, without the need to actually set up and connect to an Azure Service Bus.
Here is an example of how you could set up and use the InMemoryTestHarness to test your consumer:
[TestFixture]
public class MyConsumerTests
{
private InMemoryTestHarness _testHarness;
private MyConsumer _consumer;
[SetUp]
public void SetUp()
{
// Set up the test harness
_testHarness = new InMemoryTestHarness();
// Set up your consumer
_consumer = new MyConsumer();
// Add the consumer to the test harness
_testHarness.Consumer(_consumer);
}
[Test]
public async Task Test_MyConsumer_Handles_DatasetDownloaded_Message()
{
// Arrange
var datasetDownloadedMessage = new DatasetDownloadedMessage();
// Act
await _testHarness.Send(datasetDownloadedMessage);
// Assert
// Make assertions about how your consumer handled the message
// For example:
_consumer.Received().Consume(Arg.Is<DatasetDownloadedMessage>(m => m == datasetDownloadedMessage));
}
}
I have a video and some sample code showing how to manage and test using MassTransit.
https://www.youtube.com/watch?v=ubBW2bG0VbY&ab_channel=GarryTaylor
The talk about testing is towards the end of the video, but it's worth a read :)

Related

How can we use #RabbitListener and #JMSListener alternatively based on env?

Actually, I have on premises spring boot application which consumes rabbitMQ messages using #RabbitListener and I have migrated the same application to azure which consumes AzureServiceBus messages using #JMSListener.
We are maintaining same code for both on premises and Azure . So, because of these two listeners, I'm planning to replicate the same consumer code in two different classes with same content with two different Listeners
consumer with JMSListener:
#JmsListener(destination = "${queue}", concurrency = "${threads}", containerFactory = "defaultContainer")
public Message processMessage(#Payload final String message) {
//do stuff with same content
}
consumer with RabbitListener:
#RabbitListener(queues = "${app.rabbitmq.queue}")
public Message processMessage(#Payload final String message) {
//do stuff with same content
}
Is there any possibility of avoiding the duplicate code in two classes ? How can we handle listeners on a fly with only one consumer? Can any one please suggest me out ?
You can add both annotations to the same method with the autoStartup property set according to which Spring profile is active.
For #RabbitListener there is an autoStartup property on the annotation itself but, in both cases, there are Spring Boot properties auto-startup to control whether the container starts or not.

App receiving LiveData from Service in same apk (process) -Bad practice or not?

I have a service that collects data and has to survive the app's life-cycle changes while app is in the background. This service resides in the same process as my app, i.e. registered in the manifest as well.
The service posts LiveData to the app, and the main app retrieves this LiveData by binding to the service and doing something like:
private void onServiceConnected(TicketValidatorService service) {
...
service.getStatus().observe(this, new Observer<SomeStatus>() {
#Override
public void onChanged(SomeStatus status) {
handleStatusChanged(status);
}
})
...
}
Is this considered bad practice? Or should I rather communicate via Messenger/Handler or LocalBroadcastManager stuff over the service/app boundary? It would be difficult to put the service in another process, but I don't think I have to do that for the sake of my task.
Communication to a local service directly is not considered to be a bad practice and in fact an official recommendation. There is no reason to complicate your code to support cross-process communication when you are not going to use it. Moreover this kind of communication involves marshaling / unmarshaling which adds restrictions on data types you can pass through and has some performance hit.
Also please note, starting from android 8 there are limitations on background services. So if you are not running your service as a foreground service it's not going to be alive for long time after your app goes to background.

Enabling WCF Reading of an already existing MSMQ Queue

I have developed a WCF Self hosted service using .Net Framework 4.0.
[ServiceContract(SessionMode=SessionMode.Required)]
[ServiceKnownType(typeof(XmlDocument))]
public interface IMyMSMQ
{
[OperationContract(IsOneWay=true, Action="*")]
void OnMessageReceived(MsmqMessage<XmlDocument> msg);
}
My Class implementation of this interface looks like this.
public class MyMSMQ : IMyMSMQ, IErrorHandler
{
public void OnMessageReceived(MsmqMessage<XmlDocument> msg)
{
// Log Message To appropriate destination
Logger.LogMessage(msg);
}
}
I have tried multiple scenarios.
Scenario 1:
Launch service.
Launch Client app.
Send Message to queue using Client App
Notice that the Queue does not appear to get populated with the message because the service already read the message.
Notice that nothing else happens in the service.
Send one more message
Notice that message stays in the queue
Scenario # 2: This is similar to Scenario 1 but starting the apps were in different order
Launch Client app.
Send Message to queue using Client App
Notice that the Queue does appear to get populated with the message because the service is not started and has not read the message.
Launch service.
Notice that the message disappears.
Notice that nothing else happens in the service.
Send one more message
Notice that message stays in the queue
Every time the service starts, a message is removed from the queue so, it appears that my service IS in fact reading the message but it is not able to figure out where to send it or what to do with it once it reads the message.
I found out that the code in the WCF Library was not the problem. It was how I was defining the endpoint binding.
MsmqIntegrationBinding binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0); // set timeout to 1 minute.
binding.ReceiveErrorHandling = ReceiveErrorHandling.Fault;
this.AddServiceEndpoint(typeof(eRxMsmqWCF.IeRxMSMQ), binding, GetMQUri());
It needed to have the MsmqIntegrationBinding (which requires you to include the following using statement: using System.ServiceModel.MsmqIntegration;.
Sometimes I rely on intellisense too much. The MsmqIntegrationBinding is not present under the standard System.ServiceModel where the other bindings are located. So I used the NetMsmqBinding instead.

WCF Async callback setup for polled device

I have a WCF service setup to control a USB fingerprint reader from our .Net applications. This works fine and I can ask it to enroll users and so on.
The reader allows identification (it tells you that a particular user has presented their finger, as opposed to asking it to verify that a particular user's finger is present), but the device must be constantly polled while in identification mode for its status - when a user is detected the status changes.
What I want is for an interested application to notify the service that it wants to know when a user is identified, and provide a callback that gets triggered when this happens. The WCF service will return immediately and spawn a thread in the background to continuously poll the device. This polling could go on for hours at a time if no one tries to log in.
What's the best way to acheive this? My service contract is currently defined as follows:
[ServiceContract (CallbackContract=typeof(IBiometricCallback))]
public interface IBiometricWcfService
{
...
[OperationContract (IsOneWay = true)]
void BeginIdentification();
...
}
public interface IBiometricCallback
{
...
[OperationContract(IsOneWay = true)]
void IdentificationFinished(int aUserId, string aMessage, bool aSuccess);
...
}
In my BeginIdentification() method can I easily spawn a worker thread to poll the device, or is it easier to make the WCF service asynchronous?
I think it is much better to make the WCF service operation asynchronously. This MSDN article shows how to do it:http://msdn.microsoft.com/en-us/library/ms730059.aspx.

Slow MSMQ within a WCF service

this is a weird thing.
I created a simple SOAP based web service with WCF. When the 'SubmitTransaction' method is called, the transaction is being passed on to an application service. But if the application service is not available, it is being written to a MSMQ.
Like this:
public void SubmitTransaction(someTransaction)
{
try
{
// pass transaction data to application
}
catch(SomeError)
{
// write to MSMQ
}
}
So when an error occures the transaction is written to the queue. Now, when using the MSMQ API directly in my WCF service, everything is fine. Each call takes a few milliseconds.
E.g.:
...
catch(SomeError)
{
// write to MSMQ
var messageQueue = new MessageQueue(queuePath);
try
{
messageQueue.Send(accountingTransaction, MessageQueueTransactionType.Single);
}
finally
{
messageQueue.Close();
}
}
But since I want to use the message queue functionality at some other points of the system as well, I created a new assembly that takes care of the message queue writing.
Like:
...
catch(SomeError)
{
// write to MSMQ
var messageQueueService = new MessageQueueService();
messageQueueService.WriteToQueue(accountingTransaction);
}
Now when using this setup, the web service is suddenly very slow. From the above-mentioned milliseconds, each call now takes up to 4 seconds. Only because the message queue stuff is encapsulated in a new assembly. The logic is exactly the same. Anyone knows what the problem could be...?
Thanks!
Ok, now I know. It has something to do with my logging setup (log4net). I'll have to check that first. Sorry for stealing your time..
You have two new lines of code here:
var messageQueueService = new MessageQueueService();
messageQueueService.WriteToQueue(accountingTransaction);
Do you know which of the two is causing the problem? Perhaps add some logging, or profiling, or step through in a debugger to see which one seems slow.