How to create unit test for a service class? - c#

I have this service class code :
public class StaySearchManager
{
private readonly IPriceGridRepo _priceGridRepo;
public StaySearchManager(IPriceGridRepo priceGridRepo)
{
_priceGridRepo = priceGridRepo;
}
public async Task<IEnumerable<StaySearchResult>> Search(StaySearchParameter searchParameter)
{
if (!searchParameter.RoomIds.Any())
return new StaySearchResult[0];
PriceGrids[] grids = await _priceGridRepo.GetRoomPriceGrid(searchParameter.RoomIds);
return grids.Select(g => g.TryCreateStay(searchParameter)).Where(s => s != null).ToList();
}
}
I'm able to create unit tests (using moq) for checking that:
- if there is no room ids then we'll return an empty result
- if there is some room ids, we'll call the repo with the good parameter
But how do I unit test the stay creation process ?
The first solution would be to create a IPriceGrid itnerface and then mock it, but it seems like an over-engeneering as this interface will be there only for the unit tests.
The second solution would be to do interation tests but it will be a duplicate of my unit tests on PriceGrid.
Any third solution ?

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 I can test a particular method in my Service class using Mock C#?

Please help me with my issue. I have a Service class which is given below:
public class RateService:IRatesService
{
...
public RatesDTO GetById(int Id)
{
return Mapper.Map<Rates, RatesDTO>(this.db.Rates.GetAll().Where(m => m.RateId == Id).First());
}
}
An interface IRatesServicelooks like that sample of code:
public interface IRatesService
{
.....
RatesDTO GetById(int Id);
....
}
And now I try to test public RatesDTO GetById(int Id) method. My code is given below:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Mock<IRatesService> mock = new Mock<IRatesService>();
mock.Setup(m => m.GetById(It.IsAny<int>())).Returns<RatesDTO>(total=>total);
Assert.IsNotNull(mock.Object.GetById(1));
}
}
But when I run test I get an error like this:
Test Name: TestMethod1 Test
FullName: Provider.Tests.Services.UnitTest1.TestMethod1
Result Message:
Test method Provider.Tests.Services.UnitTest1.TestMethod1 threw
exception: System.ArgumentException: Невозможно преобразовать объект
типа "System.Int32" к типу "Provider.BLL.DTO.RatesDTO".
What is the best practice to test the Service classes and methods?
You are trying to test your mock. That doesn't make any sense.
You should strive to test your actual code.
In your case, you might want to make sure that your GetById returns RatesDTO with the right id value.
You could use Mock framework, to facilitate your testing.
e.g. if you are trying to perform a unit-test and you are using a DB layer you might want to mock the database layer GetAll function and return several objects and then run a test to check that you actually return the right object (same id).
Your RateService is the system under test. When creating mocks for your unit tests the norm is to mock the dependencies of your system under test.
So given your current service lets say it has a dependency on a data store.
public class RateService : IRatesService {
private readonly IDbContext db;
public RateService(IDbContext dbContext) {
this.db = dbContext;
}
//...
public RatesDTO GetById(int Id) {
return Mapper.Map<Rates, RatesDTO>(this.db.Rates.GetAll().Where(m => m.RateId == Id).First());
}
//...
}
IDbContext would be the dependency of the system under test.
You would mock that up when testing RateService
[TestClass]
public class RateServiceUnitTests {
[TestMethod]
public void Given_ValidId_GetById_Should_Return_Dto() {
//Arrange
var validId = 1;
var fakes = new List<Rates>() {
new Rates { RateId = validId }
};
var mock = new Mock<IDbContext>();
//Assuming IDbContext.Rates.GetAll() returns an IEnumerable<Rates>
mock.Setup(m => m.Rates.GetAll()).Returns(fakes);
var sut = new RateService(mock.Object);
//Act
var result = sut.GetById(validId);
//Assert
Assert.IsNotNull(result);
}
}
Noticed that you are also using a mapper. You should make sure that is configured for the test as well otherwise the test will fail. When using static calls in your classes they can cause issues when you try to isolate your system for testing. Try adding the mapper as a dependency as well.

How do I unit test a method to add an item to a database?

I have an item and I am adding it to the database using this method:
public Messages addItem(Item item)
{
Messages resultMessage = Messages.Success;
using (IUnitOfWork unitOfWork = new UnitOfWork())
{
IItemRepository itemRep = new ItemRepository(unitOfWork);
try
{
itemRep.Insert(item);
unitOfWork.Commit();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
resultMessage = Messages.DB_Failure;
}
}
return resultMessage;
}
Now I have to make write a unit test for this method to check if the item is being added to the database. I have no idea how I should do that, can someone help me?
Your code is coupled with the ItemRepository and the UnitOfWork implementations. Ideally you should decouple them and use mocks to verify that the right methods are called.
A possible solution:
Make the Repository a property on your unit of work
Don't create the Unit of Work directly, use a factory for that
Make the factory a dependency of your class
In your test pass a mock of the factory to the class you are testing that returns a mock of the Unit Of Work
Return a mock of the Repository on your UoW mock
Verify that the right methods are called on your Repository mock and Unit of Work mocks
This would be an example. I have used Moq as the mocking framework. And put the test method inside the class, but you can get the idea:
class MyClass
{
private readonly IUnitOfWorkFactory _factory;
public MyClass(IUnitOfWorkFactory factory)
{
_factory = factory;
}
public Messages addItem(Item item)
{
Messages resultMessage = Messages.Success;
using (IUnitOfWork unitOfWork = _factory.GetUnitOfWork())
{
try
{
unitOfWork.ItemRep.Insert(item);
unitOfWork.Commit();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
resultMessage = Messages.DB_Failure;
}
}
return resultMessage;
}
public void Test()
{
// Arrange
var factoryMock = new Mock<IUnitOfWorkFactory>();
var uowMock = new Mock<IUnitOfWork>();
var repositoryMock = new Mock<IItemRepository>();
factoryMock.Setup(f => f.GetUnitOfWork()).Returns(uowMock.Object);
uowMock.Setup(u => u.ItemRep).Returns(repositoryMock.Object);
var sut = new MyClass(factoryMock.Object);
// Act
var item = new Item();
sut.addItem(item);
// Assert
repositoryMock.Verify(r => r.Insert(item), Times.Once);
uowMock.Verify(u => u.Commit(), Times.Once);
}
}
You say that the goal is to "check if this item is added to the database".
This is something you do not normally write a unit test for because it is the responsibility of the database, which presumably you are not the one developing.
A better case for a unit test is to mock out the database and check the logic that decides to add something to the database. For instance:
A Unit of Work is described by a customer/operator.
Your component queries the database for the existence of the item.
No corresponding item exists.
Your component adds the item to the database.
This is achieved by using just a mock of the database and it is testing your code, rather than the database.
As your method currently stands, it cannot be unit tested as it's hard-coded to write to the database.
The conventional way around this is to pass an instance of IItemRepository into the method, rather than having the method create it. Do that and then you are free to create a mocked IItemRepository implementation that can report what's being written to the DB.
As other answers suggested: try to separate your class under test from difficult/slow to test dependencies like the database. You can use a number of approaches to achieve this result, but they all come down to the same:
Don't create (new up) dependencies that make unit testing difficult in the code you want to test itself (like your unitofwork/repository). Rather, ask these dependencies from the outside world (google Dependency Inversion/DI for further info).
If you want to test the implementation of the repository with a real database, I suggest you test through the public API of your repository. Don't go writing "SELECT * FROM Items" queries yourself, but use a repository.GetItem(...) method if available. That way your tests are less brittle and decoupled from the actual implementation of your repository class.

How do I execute an automated test with the option of specifying test type

How do I execute an automated test with the option of specifying it as a unit test or "light-weight integration test" without writing the same test twice and only changing the interface it depends on to make it either of the two?
Specifically, I want to execute one test and specify it as a unit test or an integration test.
Based on the mode I select, the test should generate a service interface.
I do not want to maintain two sets of identical code with the only difference being an interface:
Service for accessing external system (integration test)
MockService (unit test)
Example:
Construct testable business layer logic
It doesn't make sense to have a morphic test.
A unit test tests that a single piece of code works in isolation.
An integration tests tests that your code works when integrated into a larger codebase.
For instance, acceptance criteria and psuedocode for unit testing a viewmodel:
public TestMeViewModelTests {
public when_adding_a_warehouse_then_should_call_service_AddNewWarehouse_given_WarehouseModel {
//Arrange
var warehouseViewModel = new WarehouseViewModel { id=1 };
var service = new Mock<IService>();
var interfaceViewModel = new TestMeViewModel(service.Object);
//Act
interfaceViewModel.AddWarehouseCommand(warehouseViewModel);
//Assert
service.Verify(s=>s.AddNewWarehouse(wareHouseViewModel), Times.Once);
}
}
See, there's no cross-pollination of concerns. You're just testing that an idempotent operation is called when adding a new warehouse. If you were using an ORM, then you'd also have unit tests verifying that the dataservice calls are occurring.
If you were going to do an integration test, then your test project would be pointed to a "WarehouseTest" connectionstring that mirrors production, and your integration test might do that same logic, but then check to make sure that the warehouse that is inserted by the test is actually in your DB at the end of the test.
Okay, I think I understand what's happening now.
You want to be able to change the implementation used of an interface at runtime in order to change the location the unit tests run against.
In that case, you want some kind of abstract factory pattern.
Example:
public class ViewModel {
IService _service;
public ViewModel(IServiceFactory factory){
_service = factory.Create();
}
public void SaveWarehouse(Warehouse aWarehouse) {
_service.AddWarehouse(aWarehouse);
}
}
public interface IServiceFactory {
IService Create();
}
public class ProductionFactory : IServiceFactory { //Dependency injected
public IService Create() {
return new ProdService();
}
}
Unit Test:
public class ViewModelTest {
public void when_adding_warehouse() {
//Arrange
var aWarehouse = new WarehouseViewModel { id=1 };
var serviceFactory = new Mock<IServiceFactory>().Object);
var service = new Mock<IService>();
serviceFactory.Setup(factory => factory.Create()).Returns(service.Object);
var viewModel = new ViewModel(serviceFactory.Object);
//Act
viewModel.AddWarehouseCommand(warehouseViewModel);
//Assert
service.Verify(s=>s.AddNewWarehouse(aWarehouse), Times.Once);
}
}
Integration Test:
Your integration test will include a local internal IService implementation and a local internal IServiceFactory implementation returning the local IService implementation. All of your tests will run perfectly fine and you can control where the data goes to very easily.
Add an entry to the app config.
App Config:
<appSettings>
<add key="IsUnitTest" value="True" />
</appSettings>
Then get the key/value pair from the config file and set your service dependency based on the config value.
Test
[TestClass]
public class MyTest
{
IServices _service = null;
[TestInitialize]
public void Setup()
{
var isUnitTest = bool.Parse(ConfigurationManager.AppSettings["IsUnitTest"]);
if (isUnitTest)
{
_service = new MockService();
}
else
{
_service = new Service();
}
}
.
.
.
I disagree C Bauer. No consensus here at all. Mocks and dependency injection go a long way to solving this problem. I've seen this approach used more frequently over the last couple of years and it works fine.
Usually in Agile environments where roles are cross functional. Some teams want a single code base/solution to work from. Especially where the size of the code base is relatively small, having "unit" tests able to function as light weight Integration tests works fine. There is no black and white solution here, only the one that works best for the problem at hand. Regardless of what others say there are multiple ways to approach this problem and the solutions/approaches are growing and changing all the time.

Proper use of MOQ in a Unit Test

Given the following, is this the proper use of MOQ? I am very new to "mocking", "stubbing", "faking", etc. and just trying to wrap my head around it.
The way I understand it is that this mock is providing a known result, so when I test this service using it, the service reacts properly?
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
IQueryable<T> Query();
}
public interface ICustomerService
{
void CreateCustomer(Customer customer);
Customer GetCustomerById(int id);
}
public class Customer
{
public int Id { get; set; }
}
public class CustomerService : ICustomerService
{
private readonly IRepository<Customer> customerRepository;
public CustomerService(IRepository<Customer> customerRepository)
{
this.customerRepository = customerRepository;
}
public Customer GetCustomerById(int id)
{
return customerRepository.Query().Single(x => x.Id == id);
}
public void CreateCustomer(Customer customer)
{
var existingCustomer = customerRepository.Query().SingleOrDefault(x => x.Id == customer.Id);
if (existingCustomer != null)
throw new InvalidOperationException("Customer with that Id already exists.");
customerRepository.Add(customer);
}
}
public class CustomerServiceTests
{
[Fact]
public void Test1()
{
//var repo = new MockCustomerRepository();
var repo = new Mock<IRepository<Customer>>();
repo.Setup(x => x.Query()).Returns(new List<Customer>() { new Customer() { Id = 1 }}.AsQueryable());
var service = new CustomerService(repo.Object);
Action a = () => service.CreateCustomer(new Customer() { Id = 1 });
a.ShouldThrow<InvalidOperationException>();
}
}
I am using xUnit, FluentAssertions and MOQ.
The way I understand it is that this mock is providing a known result,
so when I test this service using it, the service reacts properly?
This statement is correct - the unit test should be verifying that the class you're testing (in this case, CustomerService) is exhibiting the behavior you desire. It's not intended to verify that its dependencies are behaving as expected (in this case, IRepository<Customer>).
Your test is good* - you're setting up your mock for the IRepository and injecting into your SystemUnderTest, and verifying that the CustomerService.CreateCustomer() function is exhibiting the behavior that you expect.
*The overall setup of the test is fine, but I'm not familiar with xUnit, so the final two line's syntax is foreign to me, but it looks like it's correct based on the semantics. For reference, you would do the last two lines in NUnit like so:
Assert.Throws<InvalidOperationException>(() => service.CreateCustomer(...));
The test looks fine to me, the mock just provides a fake repository that returns a hardcoded answer just for the test, so the test only cares about the service you're testing and don't deals with a real-life database or whatever, since you're not testing it here.
I would only add one thing to the test to be even more complete. When you setup method calls on the mocks, make sure they were really called by the system under test. After all, the service is supposed to ask the repo for some object and throw only under a certain return value. Moq in particular provides a syntax for this:
repo.VerifyAll();
What this does is simply checking that the setups you've placed before were actually called at least once. This can protect you from errors where the service just throws the exception right away without calling the repo (easy to spot in examples like yours, but with complex code it's easy to miss a call). With that line, at the end of your test, if your service didn't called the repo asking for the list (and with that specific set of parameters), the test will fail too, even if the exception was properly thrown.

Categories

Resources