How to mock IMapper which is calling inside foreachloop? - c#

C# method where I am using IMapper interface
foreach (var req in listRequestMasters)
{
var customReq = _mapper.Map<GridModel>(req);
}
by below line of code getting success assertion but not as expected result, the one record getting twice
_mockMapper.Setup(x => x.Map<GridModel>(It.IsAny<RequestMaster>())).Returns(requestGridModelMockData.FirstOrDefault());
and by below line of code getting
Message:
Moq.MockException : IMapperBase.Map(RequestMaster)
invocation failed with mock behavior Strict. All invocations on the
mock must have a corresponding setup.
_mockMapper.Setup(x => x.Map<List<GridModel>>(It.IsAny<RequestMaster>())).Returns(requestGridModelMockData);
remaining code
var result = await Service.GetHistoryRequestDetails(historyVMMockData);
Assert.Equal(JsonConvert.SerializeObject(requestGridModelMockData), JsonConvert.SerializeObject(result));

AutoMapper is a library that is already well tested on its own. So you should use the AutoMapper library also in your tests and not mock it, because you want to test your code and not others library code (or do you have also self written tests for ASP core, EF or something similar?).
In most environments you manage your mapping within individual Profiles. If not, you should do so and create within your test a fresh mapper (preferable in constructor) and use it as usual.
For example you have some DTOs:
public class Source
{
public string Name { get; set; }
}
public class Destination
{
public string Name { get; set; }
}
And somewhere else you defined the AutoMapper mappings:
public class MyProfile : Profile
{
public MyProfile()
{
CreateMap<Source, Destination>();
}
}
Then within your test class you do something like this:
public class MyTests
{
private readonly IMapper mapper;
public MyTests()
{
var config = new MapperConfiguration(cfg => cfg.AddProfile<MyProfile>());
var mapper = config.CreateMapper();
}
[Fact]
public void TestSomething()
{
var source = new Source { Name = "foo" };
var sut = new SystemUnderTest(mapper);
var result = sut.DoSomething(source);
var expected = mapper.Map<Dest>(source);
Assert.Equal(expected, result, DestinationComparer.Default);
}
}
As you can see, the system under test receives the real mapper (even if you just care for an IMapper interface). You don't create a mock, stub, puppet, you name it for 3rd party libraries. You use the real implemenations, because you write tests for your code.
Maybe it makes sense to write tests checking if a 3rd party library works as expected, which helps narrow problems down when upgrading a library and still behaves the same. But these tests don't use anything of your code and just tests some library function:
[Fact]
public void CheckMapperMapsCorrectly()
{
var source = new Source { Name = "Foo" };
var dest = mapper.Map<Destination>(source);
Assert.Equal(source.Name, dest.Name);
}
But that is something different and fully optional, depending on how much you trust each 3rd party library or makes sense if you already fall into that pit on an upgrade of a 3rd party library to avoid the same problem on next update.

Related

Unit test for void method with Interface as parameter

New to Unit testing, I have below sample code and I want to create a unit test for this , Please suggest what should i do to create a unit test for this ? any link or pointers would be helpful to start
public class UserNotification : Work
{
public override void Execute(IWorkContext iwc)
{
throw new InvalidWorkException($"some message:{iwc.Name} and :{iwc.Dept}");
}
}
Edit: using MSTest for Unit testing
First, you need a test project alongside with your regular project.
You can pick from these three:
MSTest
nUnit
xUnit
All of these should have a project template in VS2022.
xUnit is a popular one, so let's pick that. The usual naming convention for test projects is YourProject.Tests. Rename UnitTest1.cs class to UserNotificationTests.cs.
As simple as it gets, you can now start writing your tests. In xUnit, a method with [Fact] attribute is a test method.
using Xunit;
namespace MyProject.Tests
{
public class UserNotificationTests
{
[Fact]
public void Execute_Should_Throw_InvalidWorkException_With_Message()
{
}
}
}
Don't think these methods as the methods in the code, naming should be close to English sentences and should reveal the intent as a regular sentence.
Classic approach to unit testing has three phases:
Arrange: Take instances of your objects, set your expected output, mock dependencies, make them ready.
Act: Call the actual action you want to test.
Assert: Check if how your actual output relates to your expected output.
Let's start with arranging.
We need a new instance of UserNotification class so we can call Execute().
We need any dummy IWorkContext object so we can pass it. We'll use NSubstitute library for that.
// Don't forget to add using NSubstitute
// Arrange
var userNotification = new UserNotification();
var workContext = Substitute.For<IWorkContext>();
workContext.Name = "testName";
workContext.Dept = "testDept";
Now you act, and invoke your method:
// Act
Action act = () => userNotification.Execute(workContext);
And lastly we assert. I highly recommend FluentAssertations library for asserting.
// Assert
act.Should().Throw<InvalidWorkException>()
.WithMessage($"some message:{workContext.Name} and :{workContext.Dept}");
Navigate to View > Test Explorer and run your tests, you should see something similar to this:
Congratulations, you wrote your first unit test.
Here's the final version of your test code:
using FluentAssertions;
using NSubstitute;
using System;
using Xunit;
namespace MyProject.Tests
{
public class UserNotificationTests
{
[Fact]
public void Execute_Should_Throw_InvalidWorkException_With_Message()
{
// Arrange
var userNotification = new UserNotification();
var workContext = Substitute.For<IWorkContext>();
workContext.Name = "testName";
workContext.Dept = "testDept";
// Act
Action act = () => userNotification.Execute(workContext);
// Assert
act.Should().Throw<InvalidWorkException>()
.WithMessage($"some message:{workContext.Name} and :{workContext.Dept}");
}
}
public class UserNotification : Work
{
public override void Execute(IWorkContext iwc)
{
throw new InvalidWorkException($"some message:{iwc.Name} and :{iwc.Dept}");
}
}
public abstract class Work
{
public virtual void Execute(IWorkContext iwc) { }
}
public interface IWorkContext
{
public string Name { get; set; }
public string Dept { get; set; }
}
public class InvalidWorkException : System.Exception
{
public InvalidWorkException() { }
public InvalidWorkException(string message) : base(message) { }
public InvalidWorkException(string message, System.Exception inner) : base(message, inner) { }
protected InvalidWorkException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}
Writing tests feels a lot different than writing regular code. But in time you'll get the hang of it. How to mock, how to act, how to assert, these may vary depending on what you are testing. The main point is to isolate the main thing you want to unit test, and mock the rest.
Good luck!
Because your title mentions specifically that you're trying to test a method with a void return type; I infer that you've already been testing methods with actual return values, and therefore that you already have a test project and know how to run a test once it is written. If not; the answer written by Mithgroth is a good explanation on how to get started on testing in general.
Your test is defined by the behavior that you wish to test. Your snippet has no behavior, which makes it hard to give you a concrete answer.
I've opted to rewrite your example:
public class UserNotification : Work
{
public override void Execute(IWorkContext iwc)
{
var splines = iwc.GetSplines();
iwc.Reticulate(splines);
}
}
Now we have some behavior that we want to test. The test goal is to answer the following question:
When calling Execute, does UserNotification fetch the needed splines and reticulate them?
When unit testing, you want to mock all other things. In this case, the IWorkContext is an external dependency, so it should be mocked. Mocking the work context allows us to easily configure the mock to help with the testing. When we run the test, we will pass an IWorkContext object which acts as a spy. In essence, this mocked object will:
... have been set up to return a very specific set of splines, one that we chose for the test's purpose.
... secretly record any calls made to the Reticulate method, and tracks the parameters that were passed into it.
Before we get into the nitty gritty on how to mock, we can already outline how our test is going to go:
[Test]
public void ReticulatesTheContextSplines()
{
// Arrange
IWorkContext mockedContext = ...; // This comes later
UserNotification userNotification = new UserNotification();
// Act
userNotification.Execute(mockedContext);
// Assert
// Confirm that Reticulate() was called
// Confirm that Reticulate() was given the result from `GetSplines()`
}
There's your basic unit test. All that's left is to create our mock.
You can write this yourself if you want. Simply create a new class that implements IWorkContext, and give it some more public properties/methods to help you keep track of things. A very simple example would be:
public class MockedWorkContext : IWorkContext
{
// Allows the test to set the returned result
public IEnumerable<Spline> Splines { get; set; }
// History of arguments used for calls made to Reticulate.
// Each call will add an entry to the list.
public List<IEnumerable<Spline>> ReticulateArguments { get; private set; } = new List<IEnumerable<Spline>>();
public IEnumerable<Spline> GetSplines()
{
// Returns the preset splines that the test configured
return this.Splines;
}
// Mocked implementation of Reticulate()
public void Reticulate(IEnumerable<Spline> splines)
{
// Does nothing except record what you passed into it
this.ReticulateArguments.Add(splines);
}
}
This is a very simplified implementation, but it gets the job done. The test will now look like this:
[Test]
public void ReticulatesTheContextSplines()
{
// Arrange
IEnumerable<Spline> splines = new List<Spline>() { new Spline(), new Spline() }; // Just create some items here, it's random test data.
IWorkContext mockedContext = new MockedWorkContext();
mockedContext.Splines = splines;
UserNotification userNotification = new UserNotification();
// Act
userNotification.Execute(mockedContext);
// Assert - Confirm that Reticulate() was called
mockedContext.ReticulateArguments.Should().HaveCount(1);
// Confirm that Reticulate() was given the result from `GetSplines()`
mockedContext.ReticulateArguments[0].Should().BeEquivalentTo(splines);
}
This test now exactly tests the behavior of your method. It uses the mocked context as a spy to report on what your unit under test (i.e. UserNotification) does with the context that you pass into it.
Note that I am using FluentAssertions here, as I find it the most easily readable syntax. Feel free to use your own assertion logic.
While you can write your own mocks; there are mocking libraries that help cut down on the boilerplating. Moq and NSubstitute are the two biggest favorites as far as I'm aware. I personally prefer NSubstitute's syntax; but both get the job done equally well.
If you want to use nunit the documentation with example is pretty easy to follow, link below.
Nunit documentation
And I think all other unit test framework have something similar to this.
[Test]
public void Execute_WhenCalled_ThrowArgumentException()
{
//Initialize an instance of IWorkContext
var iwc = new WorkContext();
//or use a Mock object, later on in assert use
//userNotification.Execute(iwc.Object)
var iwc = new Mock<IWorkContext>();
var userNotification = new UserNotification();
Assert.Throws(typeof(InvalidWorkException), () =>
{
userNotification.Execute(iwc)
});
}

.NET 5 Class Library xUnit Tests failing when comparing objects from AutoMapper

I'm currently working out of a .NET 5 class library project with no Startup methods.
The idea behind what I'm, trying to achieve is that a developer can tap into this library and pass in an object. This object will run through the method, AutoMapper will grab the properties that align with the properties in the FirstDTO, then return a DTO that can be used throughout any other projects.
I'm relatively new to the AutoMapper bits and found this article here: How to configure Auto mapper in class library project?
I've liked this approach and have leveraged it to map a dynamic object to a DTO:
Configuration.cs
public static class Configuration
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg =>
{
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<MappingProfile>();
});
IMapper mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
Almost verbatim approach.
I have my MappingProfile.cs class:
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<dynamic, FirstDTO>();
CreateMap<dynamic, SecondDTO>();
}
}
When I call my base class I have the following method:
public class BaseLibraryClass : IBaseLibraryClass
{
public FirstDTO GetFirstObject(dynamic objectSentIn)
{
return Configuration.Mapper.Map<FirstDTO>(objectSentIn);
}
}
Which, in my though, should work.
Now when I write my xUnit unit tests, I'm having a failed Assert.Equal when comparing the FirstDTO with a built DTO:
private readonly IBaseLibraryClass baseLibraryClass = new BaseLibraryClass();
private readonly FirstDTOBuilder firstDTOBuilder = new FirstDTOBuilder();
[Fact]
public void TestSeparateObject()
{
// Arrange
FirstDTO firstDTO = firstDTOBuilder.DefaultDTO().Build();
// Act
FirstDTO result = baseLibraryClass.GetFirstObject(firstDTO);
// Assert
Assert.Equal(firstDTO, result);
}
What ends up happening when I debug this unit test, is that a DTO is built with the assigned properties via the Builder. It passes the DTO into GetFirstObject successfully with the populated properties, but when it hits the return, it returns a FirstDTO object type with properties that are all zeroed out, ultimately failing my unit test.
I feel like it's something glaringly obvious, but I cannot for the life of me figure out what's causing the properties to not map properly.
Any assistance would be greatly appreciated!
Automapper supports mapping from dynamic out of the box, no need to configure anything, so in your case removing profile from the configuration (or removing CreateMap's from the profile) should just work:
public static class Configuration
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg =>
{
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
});
IMapper mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}

Moq with Func<Foo, Task<List<Bar>>>>

Scenario:
We are in the lovely scenario of a terrible data source that requires an arcane syntax. We have built our "repository" layer to translate simple parameters (primitive values) into the correct syntax for the destination.
We would like to unit test that:
The correct filters have been applied (can be done by checking the string that the repo's helper methods create)
The (mocked) remote data source is called exactly once
The (mocked) data we have defined the remote data source as returning is passed back as the return value when we call the repo.
For example
var expectedReturn = new List<Product> { new Product { StockNumber = "123" } };
provider.Setup(x => x.Run(It.IsAny<Func<IRemoteClient, Task<List<Product>>>>(),
It.IsAny<string>())).ReturnsAsync(expectedReturn);
Moq is failing on the Setup line with a NotSupportedException. I've read probably a dozen or more SO posts and can't find out why it doesn't work.
In normal usage, the Repo will use something like:
provider.Run(x => x.GetAsync<List<Product>>(requestBuilder.Request), "foo")
Definition of run in provider interface:
Task<T> Run<T>(Func<IRemoteClient, Task<T>> action, string name);
Since the requestBuilder is injected as well, we can easily evaluate that the request is built correctly as far as the number and type of parameters, but we can't run the test at all because the Mock call fails the setup and so we never get there.
I am using Moq 4.9.0 and have tested this both on .NET Core 2.1, as well as inside LINQPad using the .NET Framework. It compiles and runs for me without any problems. I am able to run the mock setup, and I am also able to call the mocked method on the mock object, and retrieve the expected return result.
The following is my test code:
class Program
{
static void Main(string[] args)
{
var expectedReturn = new List<Product> { new Product { StockNumber = "123" } };
var provider = new Mock<IProvider>();
provider
.Setup(x => x.Run(
It.IsAny<Func<IRemoteClient, Task<List<Product>>>>(),
It.IsAny<string>()))
.ReturnsAsync(expectedReturn);
var result = provider.Object.Run(client => client.GetAsync<List<Product>>(null), "foo");
Console.WriteLine(result.Result[0].StockNumber);
}
}
public interface IProvider
{
Task<T> Run<T>(Func<IRemoteClient, Task<T>> action, string name);
}
public interface IRemoteClient
{
Task<T> GetAsync<T>(object request);
}
public class Product
{
public string StockNumber { get; set; }
}

need to create convention for ApiControllers

I have a set of working imperative code in test and I'm trying to boil it down to an essential test convention.
My test looks like the following:
[Theory, BasicConventions]
public void GetVersionOnSiteVersionControllerReturnsASiteVersion(IFixture fixture)
{
fixture.OmitAutoProperties = true;
SiteVersion expected = fixture.Create<SiteVersion>();
SiteVersion actual = null;
var sut = fixture.Create<SiteVersionController>();
var response = sut
.GetSiteVersion()
.ExecuteAsync(new CancellationToken())
.Result
.TryGetContentValue<SiteVersion>(out actual);
actual.AsSource().OfLikeness<SiteVersion>().ShouldEqual(expected);
}
I also have a customization that allows this to work, namely by setting the HttpConfiguration and HttpRequestMessage to default non-null values.
public class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
var origin = fixture.OmitAutoProperties;
fixture.OmitAutoProperties = true;
var sut = fixture.Create<SiteVersionController>();
sut.Configuration = fixture.Create<HttpConfiguration>();
sut.Request = fixture.Create<HttpRequestMessage>();
fixture.Inject<SiteVersionController>(sut);
fixture.OmitAutoProperties = origin;
}
}
First, this looks ugly, but if I use Build<>().omit().with(config).with(request), it shuts off the automoq customization which it needs to build those instances.
Second, this only works for a SiteVersionController. I'd much rather generalize this for all my ApiControllers (maybe that's a bad idea, but I won't know until I try).
Essentially my convention would be as follows:
for all ApiControllers, create them without auto properties but do set the http configuration and request message properties to default non-null values
ApiControllers are quite difficult to wire up, because you'll need to assign certain properties to them in order for everything to work. At the very least, you'll need the Request property to be assigned, because otherwise, the Controller can't invoke Request.CreateResponse. Thus, switching off auto-properties for ApiController instances isn't a good strategy. Instead, you can configure AutoFixture to wire up HttpRequestMessage instances correctly.
Web API 1
With ASP.NET Web API 1, I usually use a Customization like this:
public class WebApiCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<HttpRequestMessage>(c => c
.Do(x =>
x.Properties.Add(
HttpPropertyKeys.HttpConfigurationKey,
new HttpConfiguration())));
}
}
Since auto-properties are on by default, this is going to assign an appropriate instance of HttpRequestMessage to ApiController.Request. Together with an Auto-mocking Customization, Fixture can now create instances of all your ApiController classes.
Web API 2
With ASP.NET Web API 2 (5.0.0.0), things are a little more complicated, but with a bit of trial and error, I got this Customization to pass 808 tests:
public class WebApiCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<HttpConfiguration>(c => c
.OmitAutoProperties());
fixture.Customize<HttpRequestMessage>(c => c
.Do(x =>
x.Properties.Add(
HttpPropertyKeys.HttpConfigurationKey,
fixture.Create<HttpConfiguration>())));
fixture.Customize<HttpRequestContext>(c => c
.Without(x => x.ClientCertificate));
}
}
Conventions
If you package that into an [AutoData] attribute, you should be able to refactor your test to:
[Theory, BasicConventions]
public void GetVersionOnSiteVersionControllerReturnsASiteVersion(
SiteVersionController sut,
SiteVersion expected)
{
SiteVersion actual = null;
var response = sut
.GetSiteVersion()
.ExecuteAsync(new CancellationToken())
.Result
.TryGetContentValue<SiteVersion>(out actual);
actual.AsSource().OfLikeness<SiteVersion>().ShouldEqual(expected);
}

Approach to test public methods depending on private methods

I'm trying to add tests to a legacy code, and as I start to adding code, I get the feeling that something is wrong.
In the following code, the public method RegisterChange is calling two private methods to:
Get the object to store
Store the object
public class ChangeService {
IRepository repository;
public ChangeService(IRepository repository){
this.repository = repository;
}
public bool RegisterChange( int entityId ){
var entity = GetParsedEntity( entityId );
SaveEntity( entity );
return true;
}
private Entity GetParsedEntity( int id ) {
var entity = repository.GetEntityById( id );
return new Entity{ Name = entity.Name };
}
private void SaveEntity( Entity entity ) {
repository.Save( Entity );
}
}
public class ChangeServiceFact(){
[Fact]
public void When_valid_entity__Should_save_entity(){
var mock = new Mock<IRepository>();
var service = new ChangeService(mock.object);
var result = service.RegisterChange( 0 );
Assert.True(result);
}
}
So, when Im mocking the repository, I had to go and check the private method's code to know which operations to mock.
The problem that I'm seeing with this approach is that, because the code is testing not only the test subject (the public method) but also the private methods, is not clear which should be the test result by looking at the test subject (public method).
In the case that, later on, someone decide to modify one private method (like throwing an exception from GetParsedEntity), the test will continue to pass correctly, but the client code could fail because of this change.
In this particular case, Im using C#, XUnit and Moq, but I think is more a general testing question.
The problem that I'm seeing with this approach is that, because the code is testing not only the test subject (the public method) but also the private methods, is not clear which should be the test result by looking at the test subject (public method).
The test subject you mention has no visible effect without knowing its full contract. What the full contract here is? The mentioned public method and constructor, which takes dependency. It's the dependency that's important here and interaction with this dependency is what should be tested. Private methods are (as always) implementation detail - irrelevant to unit testing.
Having said that, let's get back to the contract. What is the actual contract of test subject (ChangeService method)? To retrieve object from repository basing on some id, create different object and save the later in the same repository. And this is your test.
[Fact]
public void ChangeService_StoresNewEntityInRepository_BasedOnProvidedId()
{
const string ExpectedName = "some name";
var otherEntity = new OtherEntity { Name = ExpectedName };
var mock = new Mock<IRepository>();
var service = new ChangeService(mock.object);
mock.Setup(m => m.GetEntityById(0)).Return(otherEntity);
service.RegisterChange(0);
mock.Verify(m => m.SaveEntity(It.Is<Entity>(e => e.Name == ExpectedName));
}

Categories