How to use Moq to mock and test an IService - c#

I have a service set up as follows:
public interface IMyService
{
void AddCountry(string countryName);
}
public class MyService : IMyService
{
public void AddCountry(string countryName)
{
/* Code here that access repository and checks if country exists or not.
If exist, throw error or just execute. */
}
}
Test.cs
[TestFixture]
public class MyServiceTest
{
[Test]
public void Country_Can_Be_Added()
{ }
[Test]
public void Duplicate_Country_Can_Not_Be_Added()
{ }
}
How do I test AddCountry and moq the repository or service. I'm really not sure what to do here or what to mock. Can someone help me out?
Frameworks I'm using:
NUnit
Moq
ASP.NET MVC

And why would you need to use moq? You don't need to mock IService. In your case you can write your test like this:
[Test]
public void Country_Can_Be_Added()
{
new MyService().AddCountry("xy");
}
[Test]
public void Duplicate_Country_Can_Not_Be_Added()
{
Assert.Throws<ArgumentException>(() => new MyService().AddCountry("yx"));
}
You would need to mock the IRepository if you had a scenario like this:
interface IRepository { bool CanAdd(string country); }
class MyService : IService
{
private IRepository _service; private List<string> _countries;
public IEnumerable<string> Countries { get { return _countries; } }
public X(IRepository service) { _service = service; _countries = new List<string>(); }
void AddCountry(string x)
{
if(_service.CanAdd(x)) {
_conntires.Add(x);
}
}
}
And a test like this:
[Test]
public void Expect_AddCountryCall()
{
var canTadd = "USA";
var canAdd = "Canadd-a";
// mock setup
var mock = new Mock<IRepository>();
mock.Setup(x => x.CanAdd(canTadd)).Returns(false);
mock.Setup(x => x.CanAdd(canAdd)).Returns(true);
var x = new X(mock.Object);
// check state of x
x.AddCountry(canTadd);
Assert.AreEqual(0, x.Countires.Count);
x.AddCountry(canAdd);
Assert.AreEqual(0, x.Countires.Count);
Assert.AreEqual(0, x.Countires.Count);
Assert.AreEqual(canAdd, x.Countires.First());
// check if the repository methods were called
mock.Verify(x => x.CanAdd(canTadd));
mock.Verify(x => x.CanAdd(canAdd));
}

You test the concrete MyService. If it takes a dependency (say on IRepository) you would create a mock of that interface and inject it into the service. As written, no mocks are needed to test the service.
The point of creating the IMyService interface is to test other classes that depend on MyService in isolation. Once you know Repository works, you don't need to test it when you're testing MyService (you mock or stub it out). Once you know MyService works, you don't need to test it when you're testing MySomethingThatDependsOnMyService.

Related

Assert that method has been called using xUnit

I have a class with a logging method that I want to test. For the example I want to check if the Console.WriteLine method has been called. This is my sample class
public class MyClass
{
public void LogSomething()
{
Console.WriteLine("Test");
}
}
and its test
public class MyClassTests
{
[Fact]
public void LogsSomething()
{
MyClass myClass = new MyClass();
myClass.LogSomething(); // Assert that Console.WriteLine has been called once
}
}
Is there something I can use? (Preferably without additional packages)
I am looking for assertions like this (Pseudo code)
Assert.Method(Console.WriteLine).ToHaveBeenCalledWith(myClass.LogSomething);
Assert.Method(Console.WriteLine).ToHaveBeenCalledWith(myClass.LogSomething).Times(3); // Check if Console.WriteLine has been called 3 times (loop inside the LogSomething method)
I think you cannot assert that out of the box.
Your best bet is using Moq or another mock framework to do something along this lines.
You should always aim for a decoupled logic using dependency injection, otherwise you will end up having a tightly coupled code that is difficult to test and will not be easy to refactor whenever a change in requirements arrives
public interface ILogger
{
public void Log();
}
public class Logger: ILogger
{
public void Log()
{
Console.WriteLine("Look mom, i'm logging");
}
}
public class MyClass
{
private readonly ILogger Logger
public MyClass(ILogger logger)
{
Logger = logger;
}
public void MyMethod()
{
//other code
Logger.Log();
}
}
public class MyClassTests
{
[Fact]
public void LogsSomething()
{
//arrange
var logger = new Mock<ILogger>();
//act
var sut = new MyClass(logger.Object);
sut.MyMethod();
//Assert
logger.Verify(foo => foo.Log(), Times.Once()); //here
//some other assertions
}
}

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

Moq: setup a generic method with mocked parameters

I've been trying to write a few tests in NUnit for my generic methods, without success. I hope I can make my situation clear, since I had to heavily paraphrase my code.
DoBusinessLogic() is the method I want to test. It calls two other methods from the base class:
public class MySvc : BaseSvc, IMySvc
{
private readonly IMyRepo _repo;
private readonly IMyConnectorClass _connector
public MySvc(IMyRepo repo) : base(repo)
{
_repo = repo;
_connector = _repo.GetConnector();
}
public async Task DoBusinessLogic(int id1, int id2){
bool doesFirstObjectExist = await CheckMainObjExists<Foo>(id1, _connector);
await CheckSubObjExists<Bar>(id2, _connector);
// further business logic
}
}
Those methods, in turn, call the same repository method, but have different logic after it:
public abstract class BaseSvc : IBaseSvc
{
private readonly IBaseRepo _repo
protected BaseSvc(IBaseRepo repo)
{
_repo = repo;
}
protected async Task<bool> CheckMainObjExists<T>(int? id, IMyConnectorClass connector)
{
return await _repo.GetObjectByIdAsync<T>(Id, connector) != null;
}
protected async Task CheckSubObjExists<T>(int? id, IMyConnectorClass connector)
{
if (await _repo.GetObjectByIdAsync<T>(Id, connector) == null)
{ throw new Exception("Object not found!"); }
}
}
Next, I want to write unit a test for DoBusinessLogic() in the MySvc class. Unfortunately, it seems I can't mock the responses from the repository.
[TestFixture]
public class MySvcTests
{
private MySvc _svc;
private Mock<IMyRepo> _repoMock;
private Mock<IMyConnectorClass> _connectorMock;
[SetUp]
public void SetUp()
{
_repoMock = new Mock<IMyRepo>() {};
_connectorMock = new Mock<IMyConnectorClass>();
_repo.SetUp(r => r.GetConnector()).Return(_connectorMock.Object);
_svc = new MySvc(_repoMock);
}
/*
My intent in this test, is to make CheckMainObjExists() pass,
but make CheckSubObjExist() fail.
*/
[Test]
public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException()
{
// This should return an object
_repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync(new Foo());
// This should return null
_repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync((Bar) null);
Assert.Throws<Exception>(await _svc.DoBusinessLogic());
}
}
However, when I run the test, both methods that I set up for my mock repo return null, whereas I expect a "true" from the first.
I do not know where the problem is situated, but I have my suspicions:
Is it possible to setup a method, using a mocked object as a parameter? In this case, is it possible to use _connectorMock.Object as a setup parameter?
Is it possible to setup the same generic method multiple times, but for a different type each time? It's first setup for Foo, then for Bar.
I just tested this code and it runs as expected. Now I had to make a lot of assumptions just to get the code to compile and run which would mean that my test of your code is flawed as I may have fixed something that was omitted in your example.
I made no changes to your test setup code, which worked.
[TestClass]
public class MySvcTests {
[TestMethod]
[ExpectedException(typeof(Exception))]
public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException() {
var _repoMock = new Mock<IMyRepo>() { };
var _connectorMock = new Mock<IMyConnectorClass>();
_repoMock.Setup(r => r.GetConnector()).Returns(_connectorMock.Object);
var _svc = new MySvc(_repoMock.Object);
// This should return an object
_repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync(new Foo());
// This should return null
_repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
.ReturnsAsync((Bar)null);
await _svc.DoBusinessLogic(0, 0);
}
}

Write unit test cases in VS2012

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

Unit testing CRUD operation in visual studio 2012

I am testing the create class in Visual Studio 2012
My controller class is:
public ActionResult Create()
{
return View();
}
//
// POST: /Member/Create
[HttpPost]
public ActionResult Create(Member member)
{
if (ModelState.IsValid)
{
db.Members.Add(member);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(member);
}
And test class is:
[TestClass]
public class MemberTest
{
[TestMethod]
public void Create(Member mem)
{
mem.MemID = 123;
mem.MemName = "sruthy";
/// dont know what is writing.
}
}
SampleDataContext.cs
public class SampleDataContext:DbContext
{
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I am stuck in test case please help me.
First - create an abstraction for your data access code (mocking DbContext is not very convenient thing):
public interface IMemberRepository
{
void Add(Member member);
}
and make your controller depend on it
public MemberController(IMemberRepository repository)
{
this.repository = repository;
}
This will allow mock data access code easily. Next - write tests which verify controller behavior (I use NUnit and Moq here):
private MemberController controller;
private Mock<IMemberRepository> repositoryMock;
private Member member;
[SetUp]
public void Setup()
{
repositoryMock = new Mock<IMemberRepository>();
controller = new MemberController(repositoryMock.Object);
member = new Member { MemID = 123, MemName = "sruthy" };
}
[Test]
public void ShouldCreateMemberWhenItIsValid()
{
var result = (RedirectToRouteResult)controller.Create(member);
Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
repositoryMock.Verify(r => r.Add(member));
}
[Test]
public void ShouldNotCreateMemberWhenItIsNotValid()
{
controller.ModelState.AddModelError("MemName", "Something wrong");
var result = (ViewResult)controller.Create(member);
Assert.That(result.ViewName, Is.Empty);
}
And write implementation:
[HttpPost]
public ActionResult Create(Member member)
{
if (ModelState.IsValid)
{
repository.Add(member);
return RedirectToAction("Index");
}
return View(member);
}
What I understood in unit testing is : "test only what your method is doing" So I think you have to test your method is doing well:
ModelState.IsValid
db.Members.Add(member)
db.SaveChanges()
But not the good behavior of ModelState or DbContext. These are tested in their own unit tests. You have to assert only the call is done.
To perform this kind of test you have to use the Dependency injection pattern and replace the real DbContext by mocks. These mocks are just asserting the call is well executed without involving the real dbContext.
I'm not a specialist in unit testing but I think you have to think all your architecture in order to decouple your objects. This allow you to replace real objects by mocks.

Categories

Resources