I am planning to use Moq for unit testing my azure service fabric application. I saw some of the examples here https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app/blob/master/ReferenceApp/Inventory.UnitTests/InventoryServiceTests.cs. The test I saw seems like actually writing to reliable dictionary and not mocking. Is there way to mock the add/remove from reliable dictionary? How do I unit test something like below
public async Task<bool> AddItem(MyItem item)
{
var items = await StateManager.GetOrAddAsync<IReliableDictionary<int, MyItem>>("itemDict");
using (ITransaction tx = this.StateManager.CreateTransaction())
{
await items.AddAsync(tx, item.Id, item);
await tx.CommitAsync();
}
return true;
}
First set up your DI in your services so that you can inject a mock StateManager. You can do that using a constructor that takes an IReliableStateManagerReplica as a parameter
public class MyStatefulService : StatefulService
{
public MyStatefulService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica)
: base(serviceContext, reliableStateManagerReplica)
{
}
}
Then in your tests, when you're creating your system under test (the service), use a mock IReliableStateManagerReplica
var reliableStateManagerReplica = new Mock<IReliableStateManagerReplica>();
var codePackageActivationContext = new Mock<ICodePackageActivationContext>();
var serviceContext = new StatefulServiceContext(new NodeContext("", new NodeId(8, 8), 8, "", ""), codePackageActivationContext.Object, string.Empty, new Uri("http://boo.net"), null, Guid.NewGuid(), 0L);
var myService = new MyService(serviceContext, reliableStateManagerReplica.Object);
And then set up the reliableStateManagerReplica to return a mock reliable dictionary.
var dictionary = new Mock<IReliableDictionary<int, MyItem>>();
reliableStateManagerReplica.Setup(m => m.GetOrAddAsync<IReliableDictionary<int, MyItem>>(name).Returns(Task.FromResult(dictionary.Object));
Finally, setup any mock behaviors on your mock dictionary.
Edit: Updated sample code to use Moq properly.
Related
I've created an application that uses the MS GitHttpClient class to read commits in an AzureDevOps project. I would like to make a unit test of the logic, so I need to mock the VssConnection and GitHttpClient. Neither of the two classes implements any interface.
I can mock the GitHttpClient and make it return commit refs when calling GitHttpClient.GetCommitsAsync(...) but when I try to mock VssConnection.GetClient<GitHttpClient>() I get the following exception
Test method mycli.Tests.Unit.Services.GitServiceTests.TestVssConnectionMock threw exception:
System.NotSupportedException: Unsupported expression: conn => conn.GetClient<GitHttpClient>()
Non-overridable members (here: VssConnection.GetClient) may not be used in setup / verification expressions.
Here is my test class. The first test TestVssConnection fails with the above exception. The second test TestGitHttpClientMock passes.
[TestClass]
public class GitServiceTests
{
[TestMethod]
public async Task TestVssConnectionMock()
{
var vssConnectionMock = new Mock<VssConnection>(new Uri("http://fake"), new VssCredentials());
var gitHttpClientMock = new Mock<GitHttpClient>(new Uri("http://fake"), new VssCredentials());
gitHttpClientMock.Setup(client => client.GetCommitsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<GitQueryCommitsCriteria>(), null, null, null, It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<GitCommitRef> { new GitCommitRef { Comment = "abc" } }));
vssConnectionMock.Setup(conn => conn.GetClient<GitHttpClient>()).Returns(gitHttpClientMock.Object);
// EXCEPTION THROWN ABOVE ^
var gitHttpClient = vssConnectionMock.Object.GetClient<GitHttpClient>();
var commits = await gitHttpClient.GetCommitsAsync("", "", new GitQueryCommitsCriteria());
Assert.IsTrue(commits.Count == 1);
}
[TestMethod]
public async Task TestGitHttpClientMock()
{
var gitHttpClientMock = new Mock<GitHttpClient>(new Uri("http://fake"), new VssCredentials());
gitHttpClientMock.Setup(client => client.GetCommitsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<GitQueryCommitsCriteria>(), null, null, null, It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<GitCommitRef> { new GitCommitRef { Comment = "abc" } }));
var commits = await gitHttpClientMock.Object.GetCommitsAsync("", "", new GitQueryCommitsCriteria());
Assert.IsTrue(commits.Count == 1);
}
}
My question is, how do I mock VssConnection.GetClient<GitHttpClient>() so it returns my mock of GitHttpClient?
Is the workaround to make a wrapper of VssConnection? And if so, how is that best done?
I am using .NET 6, MsTest and MoQ.
So far my own solution is to use the decorator pattern to wrap the VssConnection with an interface like this:
//Using decorator pattern to wrap VssConnection so it can be mocked. VssConnection is not mock-able out of the box.
public interface IVssConnection : IDisposable
{
public T GetClient<T>() where T : VssHttpClientBase => this.GetClientAsync<T>().SyncResult<T>();
public Task<T> GetClientAsync<T>(CancellationToken cancellationToken = default(CancellationToken)) where T : VssHttpClientBase;
}
public class VssConnectionWrapper : VssConnection, IVssConnection
{
public VssConnectionWrapper(Uri baseUrl, VssCredentials credentials) : base(baseUrl, credentials)
{
}
}
This way I can test the VssConnection like this:
[TestMethod]
public async Task TestVssConnectionMock()
{
var vssConnectionMock = new Mock<IVssConnection>();
var gitHttpClientMock = new Mock<GitHttpClient>(new Uri("http://fake"), new VssCredentials());
gitHttpClientMock.Setup(client => client.GetCommitsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<GitQueryCommitsCriteria>(), null, null, null, It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<GitCommitRef> { new GitCommitRef { Comment = "abc" } }));
vssConnectionMock.Setup(conn => conn.GetClient<GitHttpClient>()).Returns(gitHttpClientMock.Object);
var gitHttpClient = vssConnectionMock.Object.GetClient<GitHttpClient>();
var commits = await gitHttpClient.GetCommitsAsync("", "", new GitQueryCommitsCriteria());
Assert.IsTrue(commits.Count == 1);
}
Only chenge is
var vssConnectionMock = new Mock<VssConnection>(new Uri("http://fake"), new VssCredentials());
// REPLACED WITH:
var vssConnectionMock = new Mock<IVssConnection>();
BUT if anyone have a solution where I can just use Moq without having to create a decorator then please let me know :-)
I feel your pain. The lack of an interface for either the VssConnection class or the GitHttpClient class makes unit testing difficult.
I offer you this possible alternative which may or may NOT be any better than your existing approach:
Use the C# 'dynamic' duck typing keyword to pretend that C# is Python. :)
I did it like this:
First in your client code that you want to unit test, define the externally connecting pieces like the VssConnection and the GitHttpClient as 'dynamic' types.
public class TFSCustomLib
{
private dynamic gitClient;
public TFSCustomLib(dynamic connection)
{
gitClient = connection.GetClient<GitHttpClient>();
}
...
}
Then, in the unit test class itself define an IMock interface along with a MoqTfsConnection property and a TestMethod that uses that property like this:
public class TFSCustomLibTests
{
public interface IMock
{
public dynamic GetClient<GitHttpClient>();
public dynamic GetRepositoriesAsync();
}
private static IMock MoqTfsConnection
{
get
{
Mock<IMock> icc = new();
icc.Setup(x => x.GetClient<GitHttpClient>()).Returns(icc.Object);
icc.Setup(x => x.GetRepositoriesAsync()).Returns(
Task<List<GitRepository>>.FromResult(
new List<GitRepository>() {
new GitRepository() })); //TODO: Add any number of GitRepository instances configured for unit testing.
return icc.Object;
}
}
[TestMethod()]
public void TestTFSDependencyReporting()
{
TFSDependencyReporter testReporter = new(MoqTfsConnection);
Assert.AreEqual(1, testReporter.Reports.Count);
}
}
That should allow you to use Moq to mock out the VssConnection and GitHttpClient dependencies as needed.
Your milage may vary and your original approach may even be a better one. For me, having worked with Python for so long, I looked for a more pythonic approach. The 'dynamic' keyword fit the duck typed bill (pardon the pun.) The fact that C# eventually (after .Net 4.0 I think) provided the 'dynamic' keyword seems like maybe Python was/is ahead of the game in many ways.
I have an Azure Function as below. In the following code, I'm adding a product to the database using Repository & EF Core. Is there any way we can test it using Xunit? Currently, I'm testing this using Azure Service Bus Explorer.
[FunctionName("SaveProductData")]
public void Run([ServiceBusTrigger("mytopicname", Connection = "ServiceBusConnectionString")]
ProductItemUpdate message, ILogger log)
{
var product = new Domain.Entities.Product()
{
... prop init goes here.....
};
log.LogInformation($"Processed Product - Sain: {message.ProductId}");
_productRepository.Add(product);
}
To elaborate on scottdavidwalker's comment with a full example:
public class SaveProductDataTests
{
private readonly Mock<IProductRepository> _mockProductRepository = new Mock<IProductRepository>();
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
private readonly SaveProductData _saveProductData;
public SaveProductDataTests()
{
_saveProductData = new SaveProductData(_mockProductRepository.Object);
}
[Fact]
public void Given_When_Then()
{
// arrange
var productItemUpdate = new ProductItemUpdate();
// act
_saveProductData.Run(productItemUpdate, _mockLogger.Object);
// assert
_mockProductRepository.Verify(x => x.Add(It.Is<Product>(p => p.SomeProperty == "xyz")));
}
}
You need to create an instance of the class you are testing and mock the dependencies.
The Azure function is essentially a method (.Run()) inside the class which you can call on the instance.
In your unit test, you create the data to trigger the method and then make assertions on your mocks for what you expect to happen when the code runs for real.
I want mock lazy interface but I got object reference not set to an instance of an object exception.
Here is class under test:
public class ProductServiceService : IProductServiceService
{
private readonly Lazy<IProductServiceRepository> _repository;
private readonly Lazy<IProductPackageRepository> _productPackageRepository;
public ProductServiceService(
Lazy<IProductServiceRepository> repository,
Lazy<IProductPackageRepository> productPackageRepository)
{
_repository = repository;
_productPackageRepository = productPackageRepository;
}
public async Task<OperationResult> ValidateServiceAsync(ProductServiceEntity service)
{
var errors = new List<ValidationResult>();
if (!await _productPackageRepository.Value.AnyAsync(p => p.Id == service.PackageId))
errors.Add(new ValidationResult(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
.
.
.
return errors.Any()
? OperationResult.Failed(errors.ToArray())
: OperationResult.Success();
}
}
and here is test class
[Fact, Trait("Category", "Product")]
public async Task Create_Service_With_Null_Financial_ContactPerson_Should_Fail()
{
// Arrange
var entity = ObjectFactory.Service.CreateService(packageId: 1);
var fakeProductServiceRepository = new Mock<Lazy<IProductServiceRepository>>();
var repo= new Mock<IProductPackageRepository>();
repo.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<ProductPackageEntity, bool>>>()));
var fakeProductPackageRepository = new Lazy<IProductPackageRepository>(() => repo.Object);
var sut = new ProductServiceService(fakeProductServiceRepository.Object, fakeProductPackageRepository);
// Act
var result = await sut.AddServiceAsync(service);
// Assert
Assert.False(result.Succeeded);
Assert.Contains(result.ErrorMessages, error => error.Contains(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
}
fakeProductPackageRepository always is null. I followed this blog post but still I'm getting null reference exception.
How to mock lazy initialization of objects in C# unit tests using Moq
Update:
here is a screen that indicates fakeProductPackageRepository is null.
Here is a refactored version of your example:
[Fact, Trait("Category", "Product")]
public async Task Create_Service_With_Null_Financial_ContactPerson_Should_Fail() {
// Arrange
var entity = ObjectFactory.Service.CreateService(packageId = 1);
var productServiceRepositoryMock = new Mock<IProductServiceRepository>();
var productPackageRepositoryMock = new Mock<IProductPackageRepository>();
productPackageRepositoryMock
.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<ProductPackageEntity, bool>>>()))
.ReturnsAsync(false);
//Make use of the Lazy<T>(Func<T>()) constructor to return the mock instances
var lazyProductPackageRepository = new Lazy<IProductPackageRepository>(() => productPackageRepositoryMock.Object);
var lazyProductServiceRepository = new Lazy<IProductServiceRepository>(() => productServiceRepositoryMock.Object);
var sut = new ProductServiceService(lazyProductServiceRepository, lazyProductPackageRepository);
// Act
var result = await sut.AddServiceAsync(service);
// Assert
Assert.False(result.Succeeded);
Assert.Contains(result.ErrorMessages, error => error.Contains(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
}
UPDATE
The following Minimal, Complete, and Verifiable example of your stated issue passes when tested.
[TestClass]
public class MockLazyOfTWithMoqTest {
[TestMethod]
public async Task Method_Under_Test_Should_Return_True() {
// Arrange
var productServiceRepositoryMock = new Mock<IProductServiceRepository>();
var productPackageRepositoryMock = new Mock<IProductPackageRepository>();
productPackageRepositoryMock
.Setup(repository => repository.AnyAsync())
.ReturnsAsync(false);
//Make use of the Lazy<T>(Func<T>()) constructor to return the mock instances
var lazyProductPackageRepository = new Lazy<IProductPackageRepository>(() => productPackageRepositoryMock.Object);
var lazyProductServiceRepository = new Lazy<IProductServiceRepository>(() => productServiceRepositoryMock.Object);
var sut = new ProductServiceService(lazyProductServiceRepository, lazyProductPackageRepository);
// Act
var result = await sut.MethodUnderTest();
// Assert
Assert.IsTrue(result);
}
public interface IProductServiceService { }
public interface IProductServiceRepository { }
public interface IProductPackageRepository { Task<bool> AnyAsync();}
public class ProductServiceService : IProductServiceService {
private readonly Lazy<IProductServiceRepository> _repository;
private readonly Lazy<IProductPackageRepository> _productPackageRepository;
public ProductServiceService(
Lazy<IProductServiceRepository> repository,
Lazy<IProductPackageRepository> productPackageRepository) {
_repository = repository;
_productPackageRepository = productPackageRepository;
}
public async Task<bool> MethodUnderTest() {
var errors = new List<ValidationResult>();
if (!await _productPackageRepository.Value.AnyAsync())
errors.Add(new ValidationResult("error"));
return errors.Any();
}
}
}
A Lazy<> as a parameter is somewhat unexpected, though not illegal (obviously). Remember that a Lazy<> wrapped around a service is really just deferred execution of a Factory method. Why not just pass the factories to the constructor? You could still wrap the call to the factory in a Lazy<> inside your implementation class, but then you can just fake / mock your factory in your tests and pass that to your sut.
Or, perhaps the reason that you're passing around a Lazy<> is because you're really dealing with a singleton. In that case, I'd still create a factory and take dependencies on the IFactory<>. Then, the factory implementation can include the Lazy<> inside of it.
Often, I solve the singleton requirement (without the lazy loading) via setting a custom object scope for the dependency in my IoC container. For instance, StructureMap makes it easy to set certain dependencies as singleton or per-request-scope in a web application.
I rarely need to assert that I've done a lazy initialization on some service inside of a system-under-test. I might need to verify that I've only initialized a service once per some scope, but that's still easily tested by faking the factory interface.
The thing is that you are creating a Mock of Lazy as fakeProductServiceRepository and later on are returning that instance where just a Mock is needed.
You should change
var fakeProductServiceRepository = new Mock<Lazy<IProductServiceRepository>>();
to
var fakeProductServiceRepository = new Mock<IProductServiceRepository>();
I am trying to test the following MVC controller Action, which is calling out to Web API for a List of Products:
public ActionResult Index()
{
var model = new List<Product>();
using(HttpClient client = new HttpClient())
{
model = client.GetAsync(uri).Result.Content.ReadAsAsync<List<Product>>().Result;
}
return View(model);
}
I am trying to unit test this, have tried using Telerik JustMock to test, for example:
[TestMethod]
public void IndexDisplaysAllProducts()
{ // Not sure how to call here
var repo = Mock.Arrange(() => (new List<Product>())).Returns(
new List<Product> {
new Product(),
new Product(),
new Product()
});
var controller = new ProductsController();
var result = (ViewResult)controller.Index();
var model = (List<Product>)result.Model;
Assert.AreEqual(3, model.Count);
}
Just wondered how you would go about testing this?
Mobile atm, so excuse brevity. Implement an httpclientfactory class and Ihttpclientfactory interface, inject that to the ctor using ioc then mock during test to create a mocked instance of the http client.
Alternatively, and even simpler to test, you could use this approach to implement a factory class for something that does all of the stuff you're using the http client for (GetAsync(uri).Result.Content.ReadAsAsync>() etc)
Hth
I'm a beginner at writing unit tests and I have a test I'm trying to get working. I'll start of by explaining what I'm trying to test.
I'm trying to test a method which saves messages in a Mvc 4 project. The method is called SaveMessage and is shown below.
namespace ChatProj.Service_Layer
{
public class UserService : IUserService
{
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
private IMessageRepository _messageRepository;
-> public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
The _messageRepository.Save in the SaveMessage method is implemented in my DAL layer MessageRepository and looks like this:
public void Save()
{
context.SaveChanges();
}
This way of saving will seem a bit overcomplicated, but I structured the project this way because I didn't want the service layer (IUserService & UserService) to handle operations that could & should (i think) be handled by the Data Access Layer (IMessageRepository & MessageRepository).
Now comes the tricky part. I've been trying to understand how I could unit test this. This is my try:
namespace ChatProj.Tests
{
[TestFixture]
class MessageRepositoryTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void SaveMessage_SaveWorking_VerifyUse()
{
//Arrange
var userServiceMock = new Mock<UserService>();
var message = new Message { MessageID = 0, Name = "Erland", MessageString = "Nunit Test", MessageDate = DateTime.Now };
var repositoryMock = new Mock<IMessageRepository>();
var contextMock = new Mock<MessageContext>();
MessageRepository messageRepository = new MessageRepository(contextMock.Object);
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
//Assert
repositoryMock.Verify(m => m.Save());
userServiceMock.Verify(m => m.SaveMessage(message));
}
}
I get this error: Imgur link , and I'm not quite sure how to solve it. I've tried looking at several other SO posts but I fail to make the test work.
So I'm wondering, how do I practically get my Unit Test to work?
You should setup your MessageContext properties to return fake data and don't make real Db call with SaveChanges method.
Right now it still tries to access a real DB.
But you can setup only virtual properties or if it will be an inteface.
So the best solution is to extract an interface from your MessageContext and inject it into repository. Then you can easily mock your IMessageContext interface and force it to return appropriate in-memory data.
Take a look at these two lines:
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
You're creating a userService instance, and then immediately saving your message. Now jump into the SaveMessage code.
public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
Ok, now you're adding stuff to messageContext, and then calling _messageRepository.Save(). But where are messageContext and _messageRepository instantiated?
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
You're creating them at instantiation. The mocks that you've created in your test aren't being used. Instead of creating instances of these objects in the constructor, you might consider passing them into the UserService constructor as arguments. Then, you can pass in mocked instances in your test.