write unit testing with mock in repository pattern - c#

I have following interface and its repository class
Interface
public interface IIdentityRepository
{
bool CreateUser(ApplicationUser user, string password);
}
Repository
public class IdentityRepository : IIdentityRepository
{
ApplicationDbContext dbContext;
public IdentityRepository()
{
dbContext = new ApplicationDbContext(); // if none supplied
}
public bool CreateUser(ApplicationUser user, string password)
{
var userManager = new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(dbContext));
var idResult = userManager.Create(user, password);
return idResult.Succeeded;
}
}
public class UserManager : UserManager<ApplicationUser>
{
public UserManager()
: base(new UserStore<ApplicationUser>(new ApplicationDbContext()))
{
}
}
This is the test class I'm trying to write for CreateUser method
In this method I'm using AppplicationUser as my model.
[TestClass]
public class IdentityRepositoryTest
{
private IdentityRepository _identitityRepo;
private Mock<IIdentityRepository> _identitityRepository;
private List<ApplicationUser> _users;
// initialize the test class
[TestInitialize]
public void TestSetup()
{
_identitityRepository = new Mock<IIdentityRepository>();
_users = new List<ApplicationUser>();
_identitityRepository.Setup(m => m.CreateUser(It.IsAny<ApplicationUser>())).Callback<ApplicationUser>(c => _users.CreateUser(c));
_identitityRepo = new IdentityRepository();
}
#region Users
// check valid number of user/s(1) existing in current DB
[TestMethod]
public void IsValidtNumberofUsersExist()
{
// Arrange
_users.Add(new ApplicationUser { UserName = "Kez" , Email = "kez#gmail.com" });
// Act
var result = _identitityRepo.GetAllUsers();
Assert.IsNotNull(result);
// Assert
var numberOfRecords = result.ToList().Count;
Assert.AreEqual(1, numberOfRecords);
}
#endregion
}
But in here I'm having following compile time error
EDIT :
Once I change above error line as follows error went away.
_identitityRepository.Setup(m => m.CreateUser(It.IsAny<ApplicationUser>(),"password")).Callba‌​ck<ApplicationUser>(‌​c => _users.Add(c));
but when I run this test, I'm getting following error
Result Message: Initialization method
ProjectName.UnitTest.Common.IdentityRepositoryTest.TestSetup threw
exception. System.ArgumentException: System.ArgumentException: Invalid
callback. Setup on method with parameters (ApplicationUser,String)
cannot invoke callback with parameters (ApplicationUser)..

_identitityRepository.Setup(m => m.CreateUser(It.IsAny<ApplicationUser>(),"password"))
.Callba‌​ck<ApplicationUser>(‌​c => _users.Add(c));
Should be:
_identitityRepository.Setup(m => m.CreateUser(It.IsAny<ApplicationUser>(),"password"))
.Callba‌​ck<ApplicationUser, string>(‌​(c, s) => _users.Add(c));
https://github.com/Moq/moq4/wiki/Quickstart#callbacks

Related

Mocked method do not pass correct value

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

Mocking ApiController SignalR broadcasting

I'm trying to mock SignalR broadcasting present in ApiController(WebApi), but unable to complete test case, below is my code
SignalRHub
public class HubServer : Hub { }
ApiControllerWithHub
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub
{
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
protected IHubContext Hub
{
get { return hub.Value; }
}
}
Controller (Method to Mock)
public class NotificationController : ApiControllerWithHubController<HubServer>
{
[HttpPost]
public HttpResponseMessage SendNotification(NotificationInput notification)
{
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
}
}
I'm writing following unit test with the help of Mock SignalR Post, I'm stuck here because this is SignalR call from controller not from SignalR Hub.
MockTest
public interface IClientContract
{
void BroadcastCustomerGreeting(string message);
}
[TestMethod]
public void SendNotificationTest()
{
NotificationInput notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
// Arrange
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
var mockGroups = new Mock<IClientContract>();
// Act.
mockGroups.Setup(_ => _.BroadcastCustomerGreeting("notification")).Verifiable();
mockClients.Setup(_ => _.Group("GroupName")).Returns(mockGroups.Object);
// I'm stuck here
var controller = new NotificationController();
// Act
HttpResponseMessage actionResult = controller.SendNotification(notificationInput);
}
Any help is appreciated to complete/correct this unit test.
Redesign needed. Base ApiController tightly coupled to static accessor of the hub context. This needs to be refactored out into its own service to allow for more flexibility via constructor injection.
public interface IHubContextProvider {
IHubContext Hub { get; }
}
public class HubContextProvider<THub> : IHubContextProvider where THub : IHub {
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
public IHubContext Hub {
get { return hub.Value; }
}
}
Controllers now need to be refactored to explicitly expose its dependencies.
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub {
private readonly IHubContext hub;
public ApiControllerWithHubController(IHubContextProvider context) {
this.hub = context.Hub;
}
protected IHubContext Hub {
get { return hub; }
}
}
public class NotificationController : ApiControllerWithHubController<HubServer> {
public NotificationController(IHubContextProvider context)
: base(context) {
}
[HttpPost]
public IHttpActionResult SendNotification(NotificationInput notification) {
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
return Ok();
}
}
Test can now be exercised with necessary mocks of dependencies.
[TestMethod]
public void _SendNotificationTest() {
// Arrange
var notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
var groupName = "GroupName";
var message = "notification";
var mockGroups = new Mock<IClientContract>();
mockGroups.Setup(_ => _.BroadcastCustomerGreeting(message)).Verifiable();
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
mockClients.Setup(_ => _.Group(groupName)).Returns(mockGroups.Object).Verifiable();
var mockHub = new Mock<IHubContext>();
mockHub.Setup(_ => _.Clients).Returns(mockClients.Object).Verifiable();
var mockHubProvider = new Mock<IHubContextProvider>();
mockHubProvider.Setup(_ => _.Hub).Returns(mockHub.Object);
var controller = new NotificationController(mockHubProvider.Object);
// Act
var actionResult = controller.SendNotification(notificationInput);
//Assert
mockClients.Verify();
mockGroups.Verify();
mockHub.Verify();
}
Just make sure to register new service with DI container so that it can be injected into dependent controllers.
With the redesign the base controller can be removed all together and the hub provider used directly. This is assuming that there was not any other reason to have the base controller.

Unable to get Default Constructor

I an getting the below issue when running the Unit Test project.
Unable to get Default Constructor For class ********
[TestClass]
public class PersonRegistration
{
private ILoggingService _loggingService;
private IUserManager _userManager;
public PersonRegistration(IUserManager userManager, ILoggingService loggingService)
{
this._userManager = userManager;
this._loggingService = loggingService;
}
[TestMethod]
public void TestMethod1()
{
RegisterBindingModel model = new RegisterBindingModel();
AccountController ac = new AccountController(_userManager, _loggingService);
model.UserName = "test123#gmail.com";
var result = ac.Register(model);
Assert.AreEqual("User Registered Successfully", result);
}
How to fix that. Some answers says that to use a parameter less constructor. But here I need params.
RegisterBindingModel()
public class RegisterBindingModel
{
public RegisterBindingModel();
[Display(Name = "User name")]
[Required]
public string UserName { get; set; }
}
Issue
I've just tested this in my unit tests.
Add
public PersonRegistration()
{
}
And it should run fine.
There is no need for constructors on your unit test classses. If you are using a mocking framework like Moq then I use a factory to return the dependent moqs for the classes I'm testing.
public ILoggingService ReturnMockLoggingService()
{
var mockService = new Mock<ILoggingService>();
return mockService.Object;
}
Then in the test fixture.
[TestMethod]
public void TestMethod1()
{
RegisterBindingModel model = new RegisterBindingModel();
var logService = MockFactory.ReturnMockLoggingService();
var userService = MockFactory.ReturnMockUserService();
AccountController ac = new AccountController(userService, logService);
model.UserName = "test123#gmail.com";
var result = ac.Register(model);
Assert.AreEqual("User Registered Successfully", result);
}
if you're not using mocks then simply instance the user and log service in the test or create a SetUp.
[ClassInitialize]
public void SetUp()
{
_loggingService = new LoggingService();
_userManager = new UserManager();
}
Hope that helps.
You should use a mocking framework like Moq.
Example:
[TestClass]
public class PersonRegistration
{
[TestMethod]
public void TestMethod()
{
RegisterBindingModel model = new RegisterBindingModel();
var mockService = new Mock<ILoggingService>();//Mock
//Do something as per your requirement
//var reg= new List<RegisterBindingModel >(); // provide some sample list
//mockService .Setup(r => r.GetAll=()).Return(reg);
var mockManager = new Mock<IUserManager>();//Mock
//Do something as per your requirement
//var user= new List<User>(); // provide some sample list
//mockManager .Setup(r => r.GetAll=()).Return(user);
AccountController ac = new AccountController(mockManager.Object, mockService.Object);
model.UserName = "test123#gmail.com";
var result = ac.Register(model);
Assert.AreEqual("User Registered Successfully", result);
}
}
You can get help form this and this link.

Cannot instantiate proxy of class error

I am doing a simple unit test where when creating a Course, the Title field cannot be empty. I am having to test it with a service class that has Dependency Injection with UnitOfWork. When I debug my test, I am getting an Exception error of Can not instantiate proxy of class: ContosoUniversity.Models.CourseRepository I looked into the error, but am not able to understand how to fix the issue and the Assert statement?
Error Message Display Image
CourseRepository
public class CourseRepository : GenericRepository<Course>
{
public CourseRepository(SchoolContext context)
: base(context)
{
}
UnitOfWork
public class UnitOfWork : IDisposable, IUnitOfWork
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
}
public virtual CourseRepository GetCourseRepository()
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
CourseService
public class CourseService : ICourseService
{
private IUnitOfWork unitOfWork;
public CourseService (IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
public void Create(Course course)
{
unitOfWork.GetCourseRepository().Insert(course);
unitOfWork.Save();
}
public Course GetCourseByID(int id)
{
return unitOfWork.GetCourseRepository().GetByID(id);
}
TestMethod
[TestMethod]
public void TestMethod1()
{
var course = new Course
{
CourseID = 2210,
Title = string.Empty,
Credits = 3,
DepartmentID = 1
};
Mock<CourseRepository> mockRepo = new Mock<CourseRepository>();
mockRepo.Setup(m => m.GetByID(course.CourseID)).Returns(course);
var mockUnit = new Mock<IUnitOfWork>();
mockUnit.Setup(x => x.GetCourseRepository()).Returns(mockRepo.Object);
var myService = new CourseService(mockUnit.Object);
myService.Create(course);
//var error = _modelState["Title"].Errors[0];
//Assert.AreEqual("The Title field is required.", error.ErrorMessage);
//mockRepo.Setup(x => x.Insert(course));
}
The error says that the CourseRepository can not be initialized because it does not have parameter less constructor. Mocking framework looks for parameter less constructor first to create mock object.
If your class does not have parameterless constructor then you need to pass those parameters when you create Mock. In your case mock of CourseRepository would be created as following.
var repositoryMock = new Mock<CourseRepository>(null);
Instead of null, you can pass mock objects of the constructor parameters also.
Just use the interface when mocking.
Mock<ICourseRepository> mockRepo = new Mock<ICourseRepository>();
mockRepo.Setup(m => m.GetByID(course.CourseID)).Returns(course);
Alternatively, if your class has an internal parameterless constructor, you need to add the InternalsVisibleTo attribute to assembly.
In case of Moq, add this:
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
Or this, if you need an strong key
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
In my case, adding the [Frozen] attribute to my mock helped solve this problem.
I was also having the "cannot instantiate proxy of class error", but in my case, I was doing something like this:
[Theory, AutoMoqDate]
public async void Should_DoThis_When_ThatHappens(
Fixture fixture,
Mock<TroublesomeClass> troublesomeObject
){
var someResult = SomeObject();
troublesomeObject.Setup(o => o.SomeMethodAsync().ReturnsAsync(someResult);
// Code bellow is irrelevant...
}
For me, troublesomeObject's method was called in my suite's method, and when it got to SomeMethodAsync() is when the exception occurred.
When I added the [Frozen] tag before the troublesome object, the issue subsided.

Controller API Testing with xUnit/Moq - Controller is null

I'm new to unit testing, so my problem is probably with my code and not the Moq framework, but here goes.
I'm using .Net Core with xUnit and the Moq framework, and I'm more or less following instructions from their documentation. I'm trying to test route api/user to get all users, and the issue was on asserting that the response was an ObjectResult containing <IEnumerable<User>>. No matter what I tried, result.Value was always null. The first assertion passes fine.
I set up a console project to debug this, and found something interesting. that value of the controller in the test method in Visual Studio is null. In VS Code, the value in the debugger shows Unknown Error: 0x00000....
Below is the test:
public class UserControllerTests {
[Fact]
public void GetAll_ReturnsObjectResult_WithAListOfUsers() {
// Arrange
var mockService = new Mock<IUserService>();
var mockRequest = new Mock<IServiceRequest>();
mockService.Setup(svc => svc.GetUsers(mockRequest.Object))
.Returns(new ServiceRequest(new List<User> { new User() }));
var controller = new UserController(mockService.Object);
// Act
var result = controller.GetAll();
// Assert
Assert.IsType<ObjectResult>(result);
Assert.IsAssignableFrom<IEnumerable<User>>(((ObjectResult)result).Value);
}
}
And here is the controller:
public class UserController : Controller {
private IUserService service;
public UserController(IUserService service) {
this.service = service;
}
[HttpGet]
public IActionResult GetAll() {
var req = new ServiceRequest();
service.GetUsers(req);
if(req.Errors != null) return new BadRequestObjectResult(req.Errors);
return new ObjectResult(req.EntityCollection);
}
}
And the Service Layer:
public interface IUserService {
IServiceRequest GetUsers(IServiceRequest req);
}
public class UserService : IUserService {
private IUserRepository repo;
public IServiceRequest GetUsers(IServiceRequest req) {
IEnumerable<User> users = null;
try {
users = repo.GetAll();
}
catch(MySqlException ex) {
req.AddError(new Error { Code = (int)ex.Number, Message = ex.Message });
}
finally {
req.EntityCollection = users;
}
return req;
}
}
public interface IServiceRequest {
IEnumerable<Object> EntityCollection { get; set; }
List<Error> Errors { get; }
void AddError(Error error);
}
public class ServiceRequest : IServiceRequest {
public IEnumerable<Object> EntityCollection { get; set; }
public virtual List<Error> Errors { get; private set; }
public ServiceRequest () { }
public void AddError(Error error) {
if(this.Errors == null) this.Errors = new List<Error>();
this.Errors.Add(error);
}
}
Like I said, it's probably something I'm doing wrong, I'm thinking in the mockService.Setup() but I'm not sure where. Help please?
From the use of service.GetUsers(req) it looks like service is suppose to populate the service request but in your setup you have it returning a service request. A result which is also not used according to your code.
You need a Callback to populate whatever parameter is given to the service in order to mock/replicate when it is invoked. Since the parameter is being created inside of the method you will use Moq's It.IsAny<> to allow the mock to accept any parameter that is passed.
var mockService = new Mock<IUserService>();
mockService.Setup(svc => svc.GetUsers(It.IsAny<IServiceRequest>()))
.Callback((IServiceRequest arg) => {
arg.EntityCollection = new List<User> { new User() };
});
This should allow the method under test to flow through it's invocation and allow you to assert the outcome.

Categories

Resources