question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make ServiceBus clients and objects testeable for the SDK users

See original GitHub issue

As of this moment, the main client, services and objects in Azure.Messaging.ServiceBus (track2) are not easily mockable, making it very difficult to unit test applications that use the SDK.

Making a SDK like this, that depends heavily on cloud environment to run and not being able to mock it to unit test our code is a bad design decision, specially since it would’ve been very easy to simply define interfaces for the clients, services and objects to make it possible.

I am starting new developments now and I used Microsoft.Azure.ServiceBus (track1) in my architecture tests, but was planning on switching to the new SDK when I saw it is the new way forward. This track1 SDK is barely mockable (I only had to do a little Reflection in the Message object to set a private property), but worked. The track2 SDK clients, services and objects don’t implement any interfaces that I could be mocking in my code, and the actual classes have LOTS of private inaccessible code, making it impractical or sometimes impossible to do the mocking by inheriting them.

The way I see, there are 2 possible paths to follow to “solve” this and improve things:

  • option 1: define the required interfaces and change the classes to be implementations. To not break compatibility but allow for proper mock, the methods in the interfaces should expect only interfaces, structs or basic types and the current methods already in the classes should not change signature, but their implementation could move the the interface implementations [sample 1 bellow]
  • option 2: make the current services, clients and objects properly inheritable, by turning the constructor, methods and properties overridable and create ways to tap into “private” code with “protected” methods when necessary (like when we need to raise an event).

sample 1 - ServiceBusProcessor current code snipet

public class ServiceBusProcessor: IAsyncDisposable{
  public event Func<ProcessMessageEventArgs, Task> ProcessMessageAsync;
  public event Func<ProcessErrorEventArgs, Task> ProcessErrorAsync;
  public virtual Task StartProcessingAsync(CancellationToken cancellationToken = default){...}
}

proposed code snipet


public interface IProcessMessageEventArgs{
  IServiceBusReceivedMessage Message {get;}
  CancelationToken CancelationToken {get;}

  
}

public class ProcessMessageEventArgs : IProcessMessageEventArgs, EventArgs {
  IServiceBusReceivedMessage  IProcessMessageEventArgs.Message => this.Message;
  public ServiceBusReceivedMessage  Message {get;}
  public CancelationToken CancelationToken {get;}

  Task IProcessMessageEventArgs.CompleteMessageAsync(IServiceBusReceivedMessage message, CancellationToken cancellationToken = default){
    ...
  }

  public virtual Task CompleteMessageAsync(ServiceBusReceivedMessage message, CancellationToken cancellationToken = default) => CompleteMessageAsync(message, cancellationToken);

  ...
}

public interface IServiceBusProcessor: IAsyncDisposable{
  public event Func<IProcessMessageEventArgs, Task> ProcessMessageAsync;
  public event Func<IProcessErrorEventArgs, Task> ProcessErrorAsync;
  public virtual Task StartProcessingAsync(CancellationToken cancellationToken = default){...}
}
public class ServiceBusProcessor: IServiceBusProcessor{
  public virtual event Func<ProcessMessageEventArgs, Task> ProcessMessageAsync;
  public virtual event Func<ProcessErrorEventArgs, Task> ProcessErrorAsync;
  public virtual Task StartProcessingAsync(CancellationToken cancellationToken = default){...}
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
JoshLove-msftcommented, Mar 30, 2021

There will be a beta version with these changes released next week.

2reactions
JoshLove-msftcommented, Mar 24, 2021

@kelps the PR was merged in. Feel free to test it out using our dev feeds - https://github.com/Azure/azure-sdk-for-net/blob/master/CONTRIBUTING.md#nuget-package-dev-feed

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unit testing and mocking with the Azure SDK for .NET
To create a test service client, you can either use a mocking ... in your code with an implementation that returns a set...
Read more >
Unit testing and mocking with Azure SDK .NET
To create a test client instance, inherit from the client type and override methods you are calling in your code with an implementation...
Read more >
Samples for Mocking Client Types · Issue #17380
The Service Bus client library aims to be mockable and fully support testability. To help illustrate usage of the new API for the...
Read more >
Unit Testing · Azure/azure-sdk-for-java Wiki
Mocks in unit tests. Unit tests are aimed at testing small isolated components of code that can be predictably executed any number of...
Read more >
Unit testing for ServiceBusReceivedMessage - azure
Customers using the Azure SDK client libraries can mock service clients using Mockito with org.mockito.plugins.MockMaker .
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found