I'm trying to mock using Moq, xUnit,.Net 6, Entity framework Core, I have this service:
public class CompanyService : ICompanyService
{
private readonly ICompanyRepository _repository;
public CompanyService(ICompanyRepository repository)
{
_repository = repository;
}
public async Task<Company> Create(Company Company) => await _repository.Create(Company);
}
this is the company service interface:
public interface ICompanyService
{
Task<Company> Create(Company Company);
}
this is my company repository class:
public class CompanyRepository : ICompanyRepository
{
private readonly ApplicationDbContext _context;
public CompanyRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<Company> Create(Company Company)
{
Company.Id = Guid.NewGuid();
await _context.Companies.AddAsync(Company);
await _context.SaveChangesAsync();
return Company;
}
}
and this is its interface:
public interface ICompanyRepository
{
Task<Company> Create(Company Company);
}
this is my DbContext:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options): base(options)
{}
public DbSet<Company> Companies { get; set; }
}
and finally this is my class for testing:
public class CompanyServiceTest
{
private readonly CompanyService _sut;
private readonly Mock<ICompanyRepository> _companyRepositoryMock = new Mock<ICompanyRepository>();
public CompanyServiceTest()
{
_sut = new CompanyService(_companyRepositoryMock.Object);
}
[Fact]
public async void CreateACompanyShouldWorks()
{
//Arrange
var CompanyEntity = new Company();
CompanyEntity.Name = "Test Company";
//Act
var companyCreated = await _sut.Create(CompanyEntity);
//Assert
Assert.NotNull(companyCreated);
_companyRepositoryMock.Verify(r => r.Create(CompanyEntity));
}
}
but when I run the test I get this message error:
"Assert.NotNull() Failure"
Stack Trace:
CompanyServiceTest.CreateACompanyShouldWorks() line 31
<>c.b__128_0(Object state)
I don't know if I have to mock the ApplicationDbContext, or if I have to mock anything else, I'm Using xUnit, .Net 6, Entity framework core, also I have downloaded the Moq package.
You just forgot to setup the mock inside the Arrange phase
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<CompanyEntity>()))
.ReturnsAsync(expectedCompany);
OR
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<CompanyEntity>()).Result)
.Returns(expectedCompany);
If you don't setup the mock then it will return the default value.
If you change the MockBehaviour to strict then it will throw exception.
UPDATE #1
in the case of the method GetAllCompanies I have to create a List<Company>() and then return them ? and in the method GetCompanyById I have to create an object of Company and returns it ? I mean xUnit does not go to the database using my repository?
The short answer is yes you have to mock all the methods that you want to use on your dependency. Since the CompanyService is relying correctly on abstraction (ICompanyRepository interface) rather than on the implementation (CompanyRepository class) that's why you are not depending on the Entity Framework directly.
If you want to test your repository tier/layer/module than you have to mock the DbContext to avoid database calls. There are tons of nuget packages which can be used to ease the mocking burden.
This is the solution:
//Arrange
var CompanyEntity = new Company();
CompanyEntity.Name = "Test Company";
CompanyEntity.Id = Guid.NewGuid();
CompanyEntity.Employees = new HashSet<Employee>();
//arrange
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<Company>()))
.ReturnsAsync(CompanyEntity);
//Act
var companyCreated = await _sut.Create(CompanyEntity);
//Assert
Assert.NotNull(companyCreated);
_companyRepositoryMock.Verify(r => r.Create(companyCreated));
Related
I have the following xunit test using Moq
[Fact]
public async void Add_Valid()
{
// Arrange
var mockSet = new Mock<DbSet<CategoryDao>>();
var mockContext = new Mock<Data.Context.AppContext>();
mockContext.Setup(m => m.Categories).Returns(mockSet.Object);
var categoryProfile = new CategoryVoProfile();
var configMapper = new MapperConfiguration(cfg => cfg.AddProfile(categoryProfile));
IMapper mapper = new Mapper(configMapper);
var service = new InDbCategoryService(mockContext.Object, mapper);
// Act
await service.Add(new CategoryVo() { Name = "CreatedName1" });
// Assert
mockSet.Verify(m => m.Add(It.IsAny<CategoryDao>()), Times.Once()); // DbSet verification
mockContext.Verify(m => m.SaveChanges(), Times.Once()); // DbContext verification
}
And it throws this error:
Moq.MockException:
Expected invocation on the mock once, but was 0 times: m => m.Add(It.IsAny())
Performed invocations:
Mock<DbSet:1> (m):
No invocations performed.
When I delete the DbSet verification line and ask to verify only the DbContext, it throws this:
Moq.MockException :
Expected invocation on the mock once, but was 0 times: m => m.SaveChanges()
Performed invocations:
MockAppContext:1 (m):
AppContext.Categories = InternalDbSet
DbContext.Add(CategoryDao)
DbContext.SaveChangesAsync(CancellationToken)
The simplified service looks like this:
public class InDbCategoryService : IDataServiceAsync<CategoryVo>
{
private readonly Data.Context.AppContext context;
private readonly IMapper mapper;
public InDbCategoryService(Data.Context.AppContext context, IMapper mapper)
{
this.context = context;
this.mapper = mapper;
}
public async Task Add(CategoryVo item)
{
context.Add(entity: mapper.Map<CategoryDao>(item));
await context.SaveChangesAsync();
}
}
The category profile:
public class CategoryVoProfile : Profile
{
public CategoryVoProfile()
{
CreateMap<CategoryDao, CategoryVo>()
.ReverseMap();
}
}
Database context:
public class AppContext : DbContext
{
public AppContext() { }
public AppContext (DbContextOptions<AppContext> options) : base(options) { }
public virtual DbSet<CategoryDao> Categories { get; set; }
}
I've used this microsoft docs example for my test, but it's clear I'm missing something. Any help or advice is appreciated.
You are not testing the methods that you've called in your service. Your add method:
public async Task Add(CategoryVo item)
{
context.Add(entity: mapper.Map<CategoryDao>(item));
await context.SaveChangesAsync();
}
You'll note you're calling the DbContext.Add not the context.Categories.Add which is what you verify in your test:
mockSet.Verify(m => m.Add(It.IsAny<CategoryDao>()), Times.Once());
The same is true for your SaveChanges. You're verifying the synchronous version but calling the async one. So you need to modify what you're verifying to match what you're using.
I am trying to understand how mocking works in Xunit with AutoFixture. I have created Service and Repository classes and their interfaces. Mocked method should pass value which is different from default value.
Mocked method always pass default values instead of values which i am writing in ".Returns()". I have tried AutoConfiguredMoqCustomization but it provides completely random values which i can't get back.
Repository.cs
public class Repository : IRepository
{
public int GetInt()
{
return 999;
}
}
Service.cs
public class Service : IService
{
private readonly Repository _repository;
public Service()
{
_repository = new Repository();
}
public string GetStringFromInt()
{
return _repository.GetInt().ToString();
}
}
Test
[Fact]
public void Test()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var repositoryMock = fixture.Create<Mock<IRepository>>();
var service = fixture.Create<Service>();
repositoryMock.Setup(x => x.GetInt()).Returns(1);
var act = service.GetStringFromInt();
Assert.Equal("1", act);
}
As you see value by default in Repository is 999 and I am expecting 1 from repositoryMock but result is "999" instead of "1".
Ow I have understood my problem. When I declare parameters with auto moq testing service must be AFTER all mocked repositories
Test
[Theory, AutoMoqData]
public void Test([Frozen] Mock<IRepository> repositoryMock, Service service)
{
...
}
Attribute
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(GetDefaultFixture)
{
}
private static IFixture GetDefaultFixture()
{
return new Fixture().Customize(new AutoMoqCustomization());
}
}
You should freeze your mock first. When you call Create on AutoFixture, it will create you a new instance every time. Try the following in the modified code (where you are using an interface of the type in your constructor).
public class ServiceTests
{
private readonly IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
public ServiceTests()
{
fixture.Register<IService>(() => fixture.Create<Service>());
}
[Fact]
public void Test()
{
// Arrange
var repositoryMock = fixture.Freeze<Mock<IRepository>>();
repositoryMock.Setup(x => x.GetInt()).Returns(1);
var service = fixture.Create<IService>();
// Act
var act = service.GetStringFromInt();
// Verify
Assert.Equal("1", act);
}
}
To check that you have set up autofixture correctly, you can try the following in the unit test in future.
var repo1 = fixture.Create<IRepository>();
var repo2 = fixture.Create<IRepository>();
Assert.Equal(repo1.GetHashCode(), repo2.GetHashCode());
If the above fails, that indicates that you have not frozen a type. These lines of code have saved me so much head scratching in the past...
You are doing DI wrong, you are not injecting Repository into Your serice.
Try like this.
public class Repository : IRepository
{
public int GetInt()
{
return 999;
}
}
public class Service : IService
{
IRepository Repository;
public Service(IRepository repository)
{
this.Repository = repository;
}
public string GetStringFromInt()
{
return Repository.GetInt().ToString();
}
}
Now when you mock IRepository, you can add it to Service.
You are using a new Repository() in constructor, so you are using that implementation
For school we have to write our own WebApi using the .NET Entity Core Framework. I've written my api but when I tried to use it in swagger, it always returned a HTTP 500 error: internal server error. I downloaded Fiddler to start debugging and came across a circular dependency error in my repository but I can't figure out where this would take place.
The interface (for mock testing)
public interface IVisitorRepository
{
Visitor GetBy(string email);
void AddVisitor(Visitor visitor);
void SaveChanges();
}
The concrete class
public class VisitorRepository : IVisitorRepository
{
private readonly ApplicationDbContext _context;
private readonly DbSet<Visitor> _visitors;
public VisitorRepository(ApplicationDbContext context, IVisitorRepository visitorRepository)
{
_context = context;
_visitors = _context.Visitors;
}
public void AddVisitor(Visitor visitor)
{
_visitors.Add(visitor);
}
public Visitor GetBy(string email)
{
return _visitors.SingleOrDefault(v => v.Email == email);
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
I've scoped it in my pipeline.
It's a JWT token based login and register api (that's what we need to make) and here's my register method (the method I'm testing)
[AllowAnonymous]
[HttpPost("register")]
public async Task<ActionResult<String>> Register(RegisterDTO model)
{
IdentityUser user = new IdentityUser { UserName = model.Email, Email = model.Email };
Visitor visitor = new Visitor(model.FirstName + " " + model.LastName, model.Email, model.PhoneNumber, model.Country);
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_visitorRepository.AddVisitor(visitor);
_visitorRepository.SaveChanges();
string token = GetToken(user);
return Created("", token);
}
return BadRequest();
}
The exception:
InvalidOperationException: A circular dependency was detected for the service of type 'DigitizedApi.Models.Repositories.IVisitorRepository'. DigitizedApi.Models.Repositories.IVisitorRepository(DigitizedApi.Data.Repositories.VisitorRepository) -> DigitizedApi.Models.Repositories.IVisitorRepository
Problem is your VisitorRepository (which implements IVisitorRepository) has a dependency on IVisitorRepository itself.
Actually it should be as follows:
public class VisitorRepository : IVisitorRepository
{
private readonly ApplicationDbContext _context;
private readonly DbSet<Visitor> _visitors;
public VisitorRepository(ApplicationDbContext context)
{
_context = context;
_visitors = _context.Visitors;
}
.........
}
I'm new to write unit test cases using VS2012.
Can someone help me to write unit test cases for below method?
public myclasstype getEmployeeById(int empid)
{
// this method will return employee objects
}
Just a general outline of what you can test on the GetEmployeeById method:
[TestMethod]
public void GetEmployeeById_Id_Employee()
{
Employee employee = mockManager.MockObject<Employee>().Object;
employee.DateOfBirth = new DateTime(1970, 1, 1, 0, 0, 0);
using (RecordExpectations recorder = new RecordExpectations())
{
var dataLayer = new DataLayer();
recorder.ExpectAndReturn(dataLayer.GetEmployeeById(1), employee);
}
var company = new Company();
Employee result = company.GetEmployeeById(1);
Assert.AreEqual(result.DateOfBirth, employee.DateOfBirth);
}
It's a pretty broad question, but lets say you have an Employee class...
public class Employee
{
private IEmployeeRepository _repo;
public Employee(IEmployeeRepository repo)
{
_repo = repo;
}
public Employee GetEmployeeById(int empid)
{
return _repo.GetEmployeeById(empid);
}
}
Your Test would then need to be something like...
[Test]
public void Employee_GetEmployee_By_Id()
{
IEmployeeRepository repo = new FakeEmployeeRepository();
var employeeClass = new Employee(repo);
var employee = employee.GetEmployeeById(1);
//verify employee detail
}
This is very basic, but gives you an idea. Obviously, you will have a Fake Employee Repository which will just return a pre-setup Employee, and in production you will have a real implementation of IEmployeeRepository which will connects to a DB for example.
public interface IEmployeeRepository
{
Employee GetEmployeeById(int id);
}
public class FakeEmployeeRepository : IEmployeeRepository
{
public Employee GetEmployeeById(int id)
{
return new Employee { ... };
}
}
This is all hand typed, so there's probably errors here...it's just to give an idea though.
Below are the steps
1. Add Unit test project, Solution explorer -> Add -> New Project -> Select Test from the template -> Unit Test project.
2. Download and add Reference to the Moq library you can do that by Nuget command below. To Get Nuget Package manager console, go to Tools Menu-> Library Package Manager Console -> Library Package Manager. This should show Nuget package manager console near to debug, error window.
install-package Moq
While hitting above command make sure that you have selected your test project on the project list on Nuget Package manager console.
Lets say you have defined classes as below
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public interface IEmployeeRepository
{
Employee GetById(int id);
}
public interface IUnitOfWork
{
T GetById(int id) where T : new() ;
}
public class UnitOfWork : IUnitOfWork
{
// Implementation of IUnitOfWork
//public T GetById<T>(int id) where T: new();
//{
// return new T();
//}
}
public class EmployeeRepository : IEmployeeRepository
{
//You are injecting Unit Of Work here
public IUnitOfWork UnitOfWork { get; set; }
public Employee GetById(int id)
{
// Making call to database here;
return UnitOfWork.GetById<Employee>(id);
}
}
Add UnitTest to your UnitTest Project by right click on Unit Test project , Add -> Unit Test.
Below is sample code for your Unit Test based on your classes above.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTestProject1
{
[TestClass]
public class EmployeeUnitTest
{
Mock _unitOfWork;
IEmployeeRepository _employeeRepository;
//This will be called before each test
[TestInitialize]
public void SetUp()
{
_unitOfWork = new Mock<IUnitOfWork>();
_employeeRepository = new EmployeeRepository();
}
[TestMethod]
public void GetById_ShouldCallUnitOfWork()
{
//Arrange
const int Id = 1;
_unitOfWork.Setup(x => x.GetById<Employee>(It.IsAny<int>())).Verifiable();
//Act
_employeeRepository.GetById(Id);
//Assert
_unitOfWork.Verify(x => x.GetById<Employee>(Id), Times.Once());
}
[TestMethod]
public void GetById_ShouldRetrunEmployee()
{
//Arrange
const int Id = 1;
var expectedEmp = new Employee { Id = Id, Name= "Emp"};
_unitOfWork.Setup(x => x.GetById<Employee>(It.IsAny<int>())).Returns(expectedEmp) ;
//Act
var employee = _employeeRepository.GetById(Id);
//Assert
Assert.AreEqual(expectedEmp, employee);
}
}
}
Right clik on the method you want to write unit test for > Create UnitTest...
In Create Unit Test dialog
Tick off which methods you want to generate unit tests for:
[OK]
Enter a name for the test project
[Create]
Use Assert class to check the results
I am using nuit with moq to test my controllers.
I use a session class which has an interface and an HttpContext is injected into the constructor using ninject.
like this
public class SessionService : ISession
{
public HttpContext Context { get; set; }
public SessionService(HttpContext context)
{
this.Context = context;
}
}
public interface ISession
{
HttpContext Context { get; set; }
}
public HomeController(ISession session)
{
_session = session;
}
I think in order to test the controller I have mock the HttpContext first and then pass that object into the the construtor of the mocked ISession.
I have this so far
[Test]
public void index_returns_view()
{
//arrange
var mockHttpContext = new Mock<HttpContext>();
var mockContext = new Mock<ISession>(mockHttpContext);
var c = new HomeController(mockContext.Object);
//act
var v = c.Index() as ViewResult;
//assert
Assert.AreEqual(v.ViewName, "Index", "Index View name incorrect");
}
which builds but nunit returns the following error when the test is run
System.NotSupportedException : Type to mock must be an interface or an abstract or non-sealed class.
Thanks for all help.
Have your session take a HttpContextBase in the constructor and use that as the type of the property.
You should still be able to pass a concrete HttpContext the the session in production code.
public class SessionService : ISession
{
public HttpContextBase Context { get; set; }
public SessionService(HttpContextBase context)
{
this.Context = context;
}
}
Then fix your unit test by passing "mockHttpContext.Object" to the session constructor and that it mocks the HttpContextBase.
[Test]
public void index_returns_view()
{
//arrange
var mockHttpContext = new Mock<HttpContextBase>();
var mockContext = new Mock<ISession>(mockHttpContext.Object);
var c = new HomeController(mockContext.Object);
//act
var v = c.Index() as ViewResult;
//assert
Assert.AreEqual(v.ViewName, "Index", "Index View name incorrect");
}