Problem with matching setup in Moq - c#

I've been using Moq for the past week or so and haven't had any issues until today. I'm having a problem with getting VerifyAll() to properly match the setup of my mock.
I'm currently writing unit tests for my application's API. Here's how the application is structured:
API <==> Service <==> DAO <==> Database
With this in mind, I'm mocking the service object and then constructing an API object using the mocked service. I've written a number of unit tests already without problem up until now.
I have two instance variables like this:
private Api _api;
private Mock<IHibernateService> mockService;
I initialize these in a setup method:
[SetUp]
public void DoSetupTasks()
{
mockService = new Mock<IHibernateService>();
_api = new Api(mockService.Object);
}
Here is the unit test that is failing:
[Test]
public void TestSearchOnAllProperties()
{
mockService
.Setup(service => service.LoadAll(It.IsAny<Type>()))
.Returns(new DomainBase[0]);
var dmbs = _api.SearchOnAllProperties("search term", typeof(DomainBase));
mockService.VerifyAll();
}
The API's SearchOnAllProperties() method will subsequently make a call to the service's LoadAll() method (with some additional logic of course), so I want to verify that it's being called properly. To clarify, here's how LoadAll() is being called in SearchOnAllProperties():
public IEnumerable<DomainBase> SearchOnAllProperties(string searchTerm, Type type)
{
foreach (DomainBase dmb in _hibernateService.LoadAll(type))
{
// additional logic
}
}
However, when I run the unit test, I get a MockVerificationException stating that the given setup was not matched. I cannot figure out why as it should be calling the service's LoadAll() method.

One possible cause is that at some point before this particular test method is called, mockService is being assigned to a new instance of Mock<IHibernateService>. If that is the case, then this test method would be calling Setup on the wrong instance, which would then produce this exception.
A quick way to test this would be to use local mockService and api variables and see if the test still fails:
[Test]
public void TestSearchOnAllProperties()
{
var localMockService = new Mock<IHibernateService>();
var localApi = new Api(localMockService.Object);
localMockService
.Setup(service => service.LoadAll(It.IsAny<Type>()))
.Returns(new DomainBase[0]);
var dmbs = localApi.SearchOnAllProperties("search term", typeof(DomainBase));
localMockService.VerifyAll();
}
HTH

Related

How unit test a db repository method that calls on 2 other methods in the same repo

Problem
I want to unit test a method in my repository class that checks if a record should be updated or created new.
How do I test the main function without actually having the unit test attempt to insert or query the db?
Code
I have the following repository class:
public class WidgetRepository()
{
public bool InsertOrUpdateWidget(Widget widgetToEval)
{
var retval = false;
var existingRecord = FindExistingWidget(widgetToEval);
if (existingRecord == null)
{
retval = InsertNewWidget(widgetToEval);
}
else
{
retval = UpdateExistingWidget(widgetToEval, existingRecord);
}
return retval;
}
Unit Test
[Fact]
public void Insert_New_Widget()
{
var repo = GetEmptyRepository();
var newWidget = new Widget()
{
ID = 1,
Name= "test",
Description= "Test widget",
};
var result = repo.InsertOrUpdateWidget(newWidget);
Assert.True(result);
}
private IWidgetRepository GetEmptyRepository()
{
var repo = new Mock<IWidgetRepository >();
repo.Setup(s => s.FindExistingWidget(It.IsAny<Widget>())).Returns((Widget)null);
repo.Setup(s => s.InsertNewWidget(It.IsAny<Widget>())).Returns(true);
return repo.Object;
}
In the unit test, I'm trying to mock the FindExistingWidget method and have it return a null object. I've also mocked the insert function and have it return a true.
When I run this test, instead of returning a true, it returns false.
Edit 1
So I understand that I shouldn't mock the repo... I should just create an object of this type because I should only mock things my code needs / dependencies.
But I guess the question is then how do i prevent the code from actually attempting to connect to the db when it runs the FindExistingWidget() method or the actual InsertNewWidget method?
I just want to unit the test the logic inside the InsertorUpdate method to make sure its doing the right thing
When you want to test your repository you don't test the interface. You mock your repo when you want you want to test somehting using it. It's 'unit' test so you should test every method while it's sepereated from the others.
You should be testing WidgetRepository and not IWidgetRepository.
As the previous answers states, you are not Mocking the call to InsertOrUpdateWidget(), so its returning false (it's not even calling the code in the concrete class)
If you are going to mock your repository and you just want it to return true, then do this;
private IWidgetRepository GetEmptyRepository()
{
var repo = new Mock<IWidgetRepository >();
repo.Setup(s => s.InsertOrUpdateWidget(It.IsAny<Widget>())).Returns(true);
return repo.Object;
}
You can't mock just a portion of the WidgetRepository class. In the instance you are using above is your mock, and based on your setup above, you did not implement the function you are calling (InsertOrUpdateWidget) with repo.Setup. Since it returns a boolean, it will default to the value false. This function may be implemented in your concrete implementation of IWidgetRepository, but it isn't in your mock. The return statement return repo.Object; is not of WidgetRepository, but of a mocked version of IWidgetRepository. These are two different implementations, and only one of them implements InsertOrUpdateWidget. It isn't the one you are testing.

How to mock Func<Enum, Interface>() parameter in constructor of the tested class (sut)

In my .Net6 web app, I attempted to register service injection for 2 implementations of a single IWordRepository Interface:
WordRepositoryInMemory, working with in-memory data;
WordRepositoryDatabase with calls to the database;
Following the example set out in this article, I created an enum:
public enum WordRepositoryImplementation
{
WordRepositoryInMemory,
WordRepositoryDatabase
}
Then, in my Program.cs, I registered the two services:
builder.Services.AddScoped<WordRepositoryDatabase>();
builder.Services.AddScoped<WordRepositoryInMemory>();
builder.Services.AddTransient<Func<WordRepositoryImplementation, IWordRepository?>>(wordRepositoryProvider => key =>
{
return key switch
{
WordRepositoryImplementation.WordRepositoryInMemory => wordRepositoryProvider.GetService<WordRepositoryInMemory>(),
WordRepositoryImplementation.WordRepositoryDatabase => wordRepositoryProvider.GetService<WordRepositoryDatabase>(),
_ => null,
};
});
Then, I called it in my controller like so:
private readonly IWordRepository _wordRepositoryDatabase; // I only require one of the implementations to be called by this controller.
public DictionaryDataController(Func<WordRepositoryImplementation, IWordRepository> serviceResolver)
{
_wordRepositoryDatabase = serviceResolver(WordRepositoryImplementation.WordRepositoryDatabase);
}
Unfortunately, this added complexity messed up my tests for the controller. I am no longer able to instantiate the sut with a simple Mock.Object of the WordRepositoryDatabase service. By saying unable, I mean that I don't quite have the required experience handling delegates, yet.
In my test fixture, I tried to replace the original mock implementation of the service:
private Mock<IWordRepository> _wordRepository;
// ....
_wordRepository= new Mock<IWordRepository>();
// ....
DictionaryDataController sut = new(_wordRepositoryDatabase.Object);
To something that returns a Mock of the IWordRepository, so that I could use it in my constructor:
private Func<WordRepositoryImplementation, IWordRepository?> _funcWordRepositoryImplementation;
// ...
// ...
DictionaryDataController sut = new(_funcWordRepositoryImplementation);
However, I cannot grasp the required syntax here. The closest I got to was a parameterless Func<>() that returned the Mock.Object, but it was clearly missing something.
_funcWordRepositoryImplementation= () =>
{
return new Mock<WordRepositoryImplementation, IWordRepository>();
};
And attempts to pass some arguments to it caused their own set of errors.
What would the correct way to set up this field be?
Just use lambda expression with discard parameter which will return _wordRepositoryDatabase.Object:
DictionaryDataController sut = new(_ => _wordRepositoryDatabase.Object);

Why is IObjectMapper not initialised when unit testing a controller method?

I am using ASP.NET Boilerplate template for ASP.NET Core. I have some application services which I have successfully unit tested.
I now want to test a controller method which uses these application services.
The controller method includes mapping operation like this:
var client = ObjectMapper.Map<ClientModel>(clientResponse.ClientSummary);
On executing this method, the test fails with an exception:
Message: Abp.AbpException : Abp.ObjectMapping.IObjectMapper should be implemented in order to map objects.
Interestingly, the stack trace begins with NullObjectMapper.Map.
I am using the same initialisation for AbpAutoMapper in the unit test module as is used in the Web.Mvc module:
Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
{
cfg.AddProfiles(typeof(PortalTestModule).GetAssembly());
});
However, when executing in the context of the MVC application, the mapping operations don't cause the exception.
What is it that I am failing to initialise in the Test project in relation to AutoMapper?
I have created a repro project. See link. There is a test called GetFoos_Test that tests the controller method Index() on FoosController.
public async Task GetFoos_Test()
{
var mockFooService = new Mock<IFooAppService>();
// ...
var fooController = new FooController(mockFooService.Object);
var result = await fooController.Index();
result.ShouldNotBeNull();
}
As per #aaron's answer, property injecting IObjectMapper on the controller does solve the original error. However, it doesn't use the mappings that are part of what I am trying to test. I have created mappings in the Initialize method of the MVC module like this:
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(MyMvcModule).GetAssembly());
Configuration.Modules.AbpAutoMapper().Configurators.Add(
// Scan the assembly for classes which inherit from AutoMapper.Profile
cfg =>
{
cfg.AddProfiles(typeof(MyMvcModule).GetAssembly());
cfg.CreateMap<MyDto, MyModel>()
.ForMember(dest => dest.ReportTypeName, src => src.MapFrom(x => x.ReportType.Name));
...
1. NullObjectMapper in new instances
IObjectMapper is property-injected into an instance (e.g. controller) when the instance is injected.
Since you cannot inject a controller in a unit test, you have to set ObjectMapper directly.
// using Abp.ObjectMapping;
var fooController = new FooController(mockFooService.Object);
fooController.ObjectMapper = LocalIocManager.Resolve<IObjectMapper>(); // Add this line
2. NullObjectMapper in injected instances
Add [DependsOn(typeof(AbpAutoMapperModule))] to your test module.
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyTestModule : AbpModule
{
// ...
}

Check if call to a method is made from another method using Moq

I am quite new to Moq and I am not sure is this even possible, but let say, if I have one method named GeneratedHashedAndSaltedPassword()and I am making a call to that method from method named CheckUsersPassword() is there any chance that i can write from Unit test Moq expression that says: Verify if GeneratedHashedAndSaltedPassword is call from CheckUsersPassword method?
I will know that CheckUsersPassword method preformed correctly if it makes a call to GeneratedHashedAndSaltedPassword method without any exception.
What I have for now is not much, since I am having difficult time with Moq and it's logic.
[Test]
public void CheckIfPasswordIsHashed_Test()
{
var securityServiceMock = new Mock<User>();
securityServiceMock.Setup(m => m.CheckUsersPassword(It.IsAny<string>())).Returns(true);
securityServiceMock.VerifyAll();
}
I was trying to SetUp CheckUsersPassword, but I still don't know how or even if I can preform Verification I need. Does somebody has more experience with this kind of issue?
This is what CheckUserPassword does:
public bool CheckUsersPassword(string password)
{
return SecurityService.GenerateHashedAndSaltedPassword(password, Salt) == Password;
}
It makes simple call to GenerateHashedAndSaltedPassword() and compares result with current user password.
Important is to distinguish between code which is tested with unit test and external dependencies of this code. External dependencies are mocked with MOQ but tested code must be instantiated and called in the unit test directly.
In your question I assume you test the method CheckUsersPassword and that SecurityService is a dependency which should be mocked.
In the test you have to create instance of class (which contains the tested method) and pass mock of dependency to this tested class somehow.
[Test]
public void CheckIfPasswordIsHashed_Test()
{
// Arrange
// Mock dependency which is the service and setup
// GenerateHashedAndSaltedPassword so it does what you need
var securityServiceMock = new Mock<User>();
securityServiceMock.Setup(m => m.GenerateHashedAndSaltedPassword(
It.IsAny<string>(),
ItIsAny<Salt>())
.Returns(Password);
// TestedClass needs a place where the mocked instance can be injected,
// e.g. in constructor, or public property
var testedClass = new TestedClass(securityServiceMock.Object);
// Act
testedClass.CheckUsersPassword(password);
// Assert
securityServiceMock.Verify(m => m.GenerateHashedAndSaltedPassword(
It.IsAny<string>(),
ItIsAny<Salt>()),
Times.Once());
}

How to unit test web service with Linq

I have a web service, which I would like to do some unit testing on, however I am not sure how I can do this. Can anyone give any suggestions? Below is the webservice, it produces an object with three fields, but only when there is values in the database queue.
[WebMethod]
public CommandMessages GetDataLINQ()
{
CommandMessages result;
using (var dc = new TestProjectLinqSQLDataContext())
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
You don't need to consume your data over the WebService to Unit test it. You can just create another project in your solution with a reference to your WebService project and call directly the methods.
First up, what you've posted can't really be Unit Tested at all; by definition, a Unit Test can have only a single reason to fail; However in your case, a single test of GetDataLINQ() (the "System Under Test" or "SUT") could fail because of a problem with any of the dependencies in the function - namely, TestProjectLinqSQLDataContext and usp_dequeueTestProject.
When you call this method from a Unit test, these dependencies at present are probably beyond your control because you didn't directly create them - they are most likely created in your page classes' constructor. (Note: this is an assumption on my part, and I could be wrong)
Also, because these dependencies are at present real "live" objects, which have hard dependencies on an actual database being present, it means your tests aren't able to run independently, which is another requirement for a Unit Test.
(I'll assume your page's class file is "MyPageClass" from now on, and I will pretend it's not a web page code-behind or asmx code-behind; because as other posters have pointed out, this only matters in the context of accessing the code via HTTP which we're not doing here)
var sut = new MyPageClass(); //sut now contains a DataContext over which the Test Method has no control.
var result = sut.GetDataLINQ(); //who know what might happen?
Consider some possible reasons for failure in this method when you call sut.GetDataLINQ():
new TestProjectLinqSQLDataContext() results in an exception because of a fault in TestProjectLinqSQLDataContext's constructor
dc.usp_dequeueTestProject() results in an exception because the database connection fails, or because the stored procedure has changed, or doesn't exist.
command.Select(...) results in an exception because of some as of yet unknown defect in the CommandMessage constructor
Probably many more reasons (i.e failure to perform correctly as opposed to an exception being thrown)
Because of the multiple ways to fail, you can't quickly and reliably tell what went wrong (certainly your test runner will indicate what type of exception threw, but that requires you to at least read the stack trace - you shouldn't need to do this for a Unit Test)
So, in order to do this you need to be able to setup your SUT - in this case, the GetDataLINQ function - such that any and all dependencies are fully under the control of the test method.
So if you really want to Unit Test this, you'll have to make some adjustments to your code. I'll outline the ideal scenario and then one alternative (of many) if you can't for whatever reason implement this. No error checking included in the code below, nor is it compiled so please forgive any typos, etc.
Ideal scenario
Abstract the dependencies, and inject them into the constructor.
Note that this ideal scenario will require you to introduce an IOC framework (Ninject, AutoFAC, Unity, Windsor, etc) into your project. It also requires a Mocking framework (Moq, etc).
1. Create an interface IDataRepository, which contains a method DequeueTestProject
public interface IDataRepository
{
public CommandMessages DequeueTestProject();
}
2. Declare IDataRepository as a dependency of MyPageClass
public class MyPageClass
{
readonly IDataRepository _repository;
public MyPageClass(IDataRepository repository)
{
_repository=repository;
}
}
3. Create an actual implementation of IDataRepository, which will be used in "real life" but not in your Unit Tests
public class RealDataRepository: IDataRepository
{
readonly MyProjectDataContext _dc;
public RealDataRepository()
{
_dc = new MyProjectDataContext(); //or however you do it.
}
public CommandMessages DequeueTestProject()
{
var command = dc.usp_dequeueTestProject();
result = command.Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return result;
}
}
This is where you will need to involve your IOC framework such that it can inject the correct IDataRepository (i.e RealDataRepository) whenever your MyPageClass is instantiated by the ASP.NET framework
4. Recode your GetDataLINQ() method to use the _repository member
public CommandMessages GetDataLINQ()
{
CommandMessages result;
return _repository.DequeueTestProject();
}
So what has this bought us? Well, consider now how you can test against the following specification for GetDataLINQ:
Must always invoke DequeueTestProject
Must return NULL if there is no data in the database
Must return a valid CommandMessages instance if there is data in the database.
Test 1 - Must always invoke DequeueTestProject
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to just return null; we don't care about the return value for now
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
//create the SUT, passing in the fake repository
var sut = new MyPageClass(repo.Object);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
repo.Verify(r=>r.DequeueTestProject(),Times.Once);
}
Test 2 - Must return NULL if there is no data in the database
public void GetDataLINQ_ReturnsNULLIfDatabaseEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(null);
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNull(actual);
}
Test 3 - Must return a valid CommandMessages instance if there is data in the database.
public void GetDataLINQ_ReturnsNCommandMessagesIfDatabaseNotEmpty()
{
//create a fake implementation of IDataRepository
var repo = new Mock<IDataRepository>();
//set it up to return null;
repo.Setup(r=>r.DequeueTestProject()).Returns(new CommandMessages("fake","fake","fake");
var sut = new MyPageClass(repo.Object);
//call the method but store the result this time:
var actual = sut.GetDataLINQ();
//Verify that the result is indeed NULL:
Assert.IsNotNull(actual);
}
Because we can Mock the IDataRepository interface, therfore we can completely control how it behaves.
We could even make it throw an exception, if we needed to test how GetDataLINQ responds to unforseen results.
This is the real benefit of abstracting your dependencies when it comes to Unit Testing (not to mention, it reduces coupling in your system because dependencies are not tied to a particular concrete type).
Not Quite ideal method
Introducing an IOC framework into your project may be a non-runner, so here is one alternative which is a compromise. There are other ways as well, this is just the first that sprang to mind.
Create the IDataRepository interface
Create the RealDataRepository class
Create other implementations of IDataRepository, which mimic the behaviour we created on the fly in the previous example. These are called stubs, and basically they are just classes with a single, predefined behaviour that never changes. This makes then ideal for testing, because you always know what will happen when you invoke them.
public class FakeEmptyDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return null;}
//CallCount tracks if the method was invoked.
public int CallCount{get;private set;}
}
public class FakeFilledDatabaseRepository:IDataRepository
{
public CommandMessages DequeueTestProject(){CallCount++;return new CommandMessages("","","");}
public int CallCount{get;private set;}
}
Now modify the MyPageClass as per the first method, except do not declare IDataRepository on the constructor, instead do this:
public class MyPageClass
{
private IDataRepository _repository; //not read-only
public MyPageClass()
{
_repository = new RealDataRepository();
}
//here is the compromise; this method also returns the original repository so you can restore it if for some reason you need to during a test method.
public IDataRepository SetTestRepo(IDataRepository testRepo)
{
_repository = testRepo;
}
}
And finally, modify your unit tests to use FakeEmptyDatabaseRepository or FakeFilledDatabaseRepository as appropriate:
public void GetDataLINQ_AlwaysInvokesDequeueTestProject()
{
//create a fake implementation of IDataRepository
var repo = new FakeFilledDatabaseRepository();
var sut = new MyPageClass();
//stick in the stub:
sut.SetTestRepo(repo);
//call the method
sut.GetDataLINQ();
//Verify that repo.DequeueTestProject() was indeed called.
var expected=1;
Assert.AreEqual(expected,repo.CallCount);
}
Note that this second scenario is not an ivory-tower-ideal scenario and doesn't lead to strictly pure Unit tests (i.e if there were a defect in FakeEmptyDatabaseRepository your test could also fail) but it's a pretty good compromise; however if possible strive to achieve the first scenario as it leads to all kinds of other benefits and gets you one step closer to truly SOLID code.
Hope that helps.
I would change your Code as follows:
public class MyRepository
{
public CommandMessage DeQueueTestProject()
{
using (var dc = new TestProjectLinqSQLDataContext())
{
var results = dc.usp_dequeueTestProject().Select(c => new CommandMessages(c.Command_Type, c.Command, c.DateTimeSent)).FirstOrDefault();
return results;
}
}
}
Then code your Web Method as:
[WebMethod]
public CommandMessages GetDataLINQ()
{
MyRepository db = new MyRepository();
return db.DeQueueTestProject();
}
Then Code your Unit Test:
[Test]
public void Test_MyRepository_DeQueueTestProject()
{
// Add your unit test using MyRepository
var r = new MyRepository();
var commandMessage = r.DeQueueTestProject();
Assert.AreEqual(commandMessage, new CommandMessage("What you want to compare"));
}
This allows your code to be reusable and is a common design pattern to have Data Repositories. You can now use your Repository Library everywhere you need it and test it in only one place and it should be good everywhere you use it. This way you don't have to worry about complicated tests calling WCF Services. This is a good way of testing Web Methods.
This is just a short explanation and can be improved much more, but this gets you in the right direction in building your Web Services.

Categories

Resources