real purpose of moq framework - c#

I've been asked to write unit tests using Moq framework. I'm fairly new on how to write Moq tests in c#.
I'm going through this MSDN link
Here is what I'm doing right now as we are using dependency injection on repository
//Repository
public interface IRepo
{
IQueryable<MyModel> GetById( long userId );
}
public class Repo : BaseManager, IRepo
{
public Repo(myDbContext context)
{
dbContext = context; //dbContext is from BaseManager class
}
public IQueryable<MyModel> GetById( long userId )
{
return dbContext.MyModel.Where(x => x.IsActive && x.UserId == userId );
}
}
//Test class
public class Test
{
Mock<DbSet<MyModel>> mockSet;
Mock<myDbContext> mockContext;
Mock<IRepo> mockRepository;
[TestInitialize]
public void Setup()
{
var data = new List<MyModel>{
//3 records
}.AsQueryable();
var mockSet = new Mock<DbSet<MyModel>>();
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<myDbContext>();
mockContext.Setup(c => c.MyModel).Returns(mockSet.Object);
mockRepository = new Mock<IRepo>();
mockRepository.Setup(m => m.GetById(It.IsAny<long>())).Returns(data); //Here the GetById method is set to return all 3 records set in data object.
}
[TestMethod]
public void Test_Mock_For_Nothing()
{
var controller = new MyController(mockRepository.Object);
var result = controller.GetById(1); //this will call GetById method in the repository
Assert.AreEqual(result.Count(), 1);//This will fail as we will get count as 3
}
}
So, the logic in the repository is never executed though I mocked context and repository. As GetById method would directly return the result with 3 records as per dummy data.
I'm expecting the dummy data to be filtered out based on the logic in the repository method. Is this possible with Moq ?
What is the real purpose of using Moq framework when the repository code is not being executed ?

Given that you've mocked your repository, without seeing the Controller logic, I'm not sure why you would need to mock the dbContext. But effectively with this test you are testing the Controller logic and not the repository as you've mocked the repository and what is returned from the GetById in the repository.
If you wish to test the filter logic in the repository, you would need to mock the dbContext (as you have done) and in the test create a new concrete Repository instance and test the data that is returned from a call to GetById.
So you mock dbContext.MyModel, returning your three items and let the Where call perform the filtering.
There's plenty of useful information out there regarding use of a mocking framework, but everyone has slightly differing opinions about what you should test and small a unit you should test in a single unit test, experience and personal preference is the key here.

In terms of your test I would say there is very little benefit to using a mocking framework or even having this test. My thoughts are:
1) If you have a repository write an integration test as you want to prove that you are returning data from the database/web service etc
2) Use Moq or RhinoMocks in situations where you want to test some business logic/behaviour

with Unit tests you try to test/harden your Business logic. in your repositories should not be any BL (Businesslogic). with your MOCK Framework you disable think you don´t want to test. -> Repository = access to Data.
With this you are able to change your way you get your data (repository) without any changes on your Businesslogic/UnitTests :)
PS: if you want to test your Repositories or even more you should aim to integration tests or even to End to End tests.

Related

Using Moq, is it possible to setup mocked tables by type?

I have the following code where I'm trying to setup the mocked table based on the data type passed to the MockDbSet method.
private Mock<DbContext> mockContext = new Mock<DbContext>();
public DbContext GetContext()
{
return mockContext.Object;
}
public void MockDbSet<T>(params T[] sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
mockContext.Setup(c => c.Set(typeof(T))).Returns(dbSet.Object);
}
I get the following error at the mockContext.Setup line (22):
System.NotSupportedException: Conversion between generic and non-generic DbSet objects is not supported for test doubles.
I've tried
mockContext.Setup(c => c.Set<T>()).Returns(dbSet.Object);
This does not throw the exception, but also does not setup any data.
Is it possible to setup tables this way?
Thanks
To outline mocking at the Repository level:
Given Service / Controller code that interacts with a Repostory through a contract interface:
public interface IOrderRepository
{
IQueryable<Order> GetOrderById (int orderId);
IQueryable<Order> GetOrdersForCustomer (int customerId);
}
This is the preferred repository pattern I use. Returning IQueryable means that my consumers can take advantage of deferred execution to decide how the details will be used, resulting in more efficient queries. (I.e. using .Select() to get the fields they want, doing .Count() or .Any(), .FirstOrDefault(), or .Skip().Take() etc.)
alternatively you might use generic repositories:
public interface IRepository<Order>
{
Order GetOrderById (int orderId);
ICollection<Order> GetOrdersForCustomer (int customerId);
}
The repository methods would contain minimal to no business logic. In my case the repository would only be concerted with:
Authorization (retrieve data based on the current user / tenant)
Active / Soft-Delete state. (retrieve "active" data in a soft-delete environment unless told otherwise.)
Temporal state. (Retrieve "current" date unless told otherwise.)
All business logic should reside in your service classes or controllers, where it can be tested in isolation. To test the above 3 conditions (if applicable) I use integration tests. These conditions are very low-level checks and would not change on any regular basis.
Lets say the code under test is in a Controller.
public class OrderController : IOrderController
{
private readonly IOrderRepository _repository = null;
private readonly IUnitOfWorkFactory _uowFactory = null;
public OrderController(IUnitOfWorkFactory uowFactory, IOrderRepository repository)
{
if (uowFactory == null)
throw new ArgumentNullException("uowFactory");
if (repository == null)
throw new ArgumentNullException("repository");
_uowFactory = uowFactory;
_repository = repository;
}
public void SomeActionOnOrder(int orderId)
{
using (var unitOfWork = _uowFactory.Create())
{
var order = _repository.GetOrderById(orderId)
// Here lies your validation checks that the order was found,
// business logic to do your behaviour.. This is the stuff you want to test..
// ...
unitOfWork.Commit();
}
}
}
Now when you go to test your controller...
[Test]
public void EnsureSomeActionOnOrderDoesIt()
{
var uowMock = new Mock<IUnitOfWork>();
var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
var repositoryMock = new Mock<IOrderRepository>();
var testOrderId = -1;
var stubOrders = new [] { newOrder { /* populate expected data... */ } };
uowMock.Setup(x=>x.Commit());
uowFactoryMock.Setup(x=>x.Create()).Returns(uowMock.Object);
repositoryMock.Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());
var testController = new OrderController(uowFactoryMock.Object, repositoryMock.Object);
testController.SomeActionOnOrder(testOrderId);
// Everything "touched" as expected? (did the code fetch the object? did it save the changes?)
uowFactoryMock.VerifyAll();
uowMock.VerifyAll();
repositoryMock.VerifyAll();
// Perform asserts on your stub order if SomeAction modified state as you expected.
}
Integration tests against an actual database would handle any logic that the repositories would be expected to cover.
The repository pattern I have above is the IQueryable flavour, alternatively if you return an entity, just return the "stubs" with a stub order and return it.
The mocking framework I use is Moq. The above code may not be fully syntactically correct, based solely on memory. :)
The goal of unit tests, as far as TDD/BDD go, is that these tests should be reliably repeatable, and fast to execute so that they can be run repeatedly and frequently as you are developing. Keeping repositories relatively thin, and not touching on the business logic decisions means that they can serve as a reliable cut-off point for unit tests to mock out. The repository's job is to return data, so by mocking at that point it means we can control the data we expect the code under test to work with. We can mock it to return objects, null, throw exceptions, whatever our test scenario expects our code under test to handle.
In the above example I also demonstrate the use of a basic Unit of Work pattern which wraps the DB Context. The implementation that I use for EF is Medhime's DB Context Scope Factory/Locator. Using the Unit of Work pattern we also have mocks that can verify that the code under test is (or is not) saving data for instance. The repository would need to have a link to a unit of work (initialized in a constructor, or "located" as-per the Mehdime pattern) but we don't care about that aspect when testing our services & controllers, the repository is merely mocked out and its purpose is to return and (optionally) create data.
I'll have my repositories serve as factories for entities (I.e. CreateOrder() with list of product details & quantities) to ensure that new entities are initialized with all expected referential links and required data rather than relying on calling code. That calling code would have to be littered with extra queries etc. to retrieve referential data for a new order, so instead I have it pass the view model data through to the Order Repository to resolve, wire-up, and return a valid new Order entity.
In a recent project, I created an extension method of a List<T> (could be IEnumerable, or whatever).
public static Mock<DbSet<T>> MockList<T>(this List<T> list) where T: class
{
var mockDbSet = new Mock<DbSet<T>>();
var queryable = list.AsQueryable();
mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockDbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockDbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
return mockDbSet;
}
It is then quite simple to call.
var myData = new List<MyDataType> { new MyDataType(), new MyDataType(), ....};
var mockDb = new Mock<MyContext>();
mockDb.Setup(x => x.MyDatas).Returns(myData.MockList().Object);

Entity Framework 6 and Unit Test

I have been looking around for a solution but I couldn't find the answer (like here and here.)
public class ItemsRepository {
public ItemDto Get(int id) {
using (var db = new ItemContext()) {
return db.Items.FirstOrDefault(i => i.Id == id)
.ToDto();
}
}
}
I used to test this code by going all the way to the DB. I know this is not a good practice, since the unit test in this case tests the connection to the database as well.
Ideally, I want to build an in-memory database and seed it. How would I do that in this case? How do I fake ItemContext to use an in-memory list?
Note that I don't want to expose Context as a constructor, since the user will have to know about how the data is stored.
You cannot fake ItemContext because new keyword always creates a new instance of the object. Ideally, you should inject your context by dependency injection. Something like this:
public class ItemsRepository {
public ItemDto Get(int id) {
return _itemContextService.Items.FirstOrDefault(i => i.Id == id)
.ToDto();
}
}
In unit test _itemContextService should be injected and _itemContextService.Items should be configured with mock data. All logic which you should unit test is:
FirstOrDefault(i => i.Id == id).ToDto();
This is only what Get(int id) method does. Connection with database is beyond of scope in unit testing this method.
Anyway, if you cannot use some DI container or somehow inject ItemContext then you can mock your connection string in unit test project.

Unit Testing a Web API with a Json Return

I'm brand new to unit testing and I need to do this for a current project. I have plenty of examples for testing model classes and MVC controllers, but I have a couple of web API controllers that have a Json return that I need to unit test. What should I be testing with these, and how can I do that?
First example taking no parameters
public class DefaultController : ApiController
{
private TestEntities db = new TestEntities();
[AcceptVerbs("GET")]
public IHttpActionResult FirstAPI()
{
var myQuery = (from p in db.Participants
select new
{
p.ID,
p.Name,
p.MemberType
});
return Json(myQuery);
}
}
Second example taking two parameters
public class DefaultController : ApiController
{
private TestEntities db = new TestEntities();
[AcceptVerbs("GET")]
public IHttpActionResult SecondAPI(int id, string name)
{
var myQuery = (from p in db.Participants
where p.ID == id && p.Name == name
select new
{
p.ID,
p.Name,
p.MemberType
});
return Json(myQuery);
}
}
You'd unit test it the same way you unit test anything... Invoke it and examine the results. In this case the result is of type HttpActionResult, which appears to have only one operation on it.
So your test will likely need to also invoke that operation, probably awaiting it since it's async, and examine the results of that which appear to be of type HttpResponseMessage.
That type has properties you can examine to validate the result of the operation you're testing. The most important property likely being Content, which contains the contents of the response. Your test will basically read those contents and validate them against an expected result.
The bigger problem here isn't actually validating the result, that's easy once you peer into the returned value as described above. The real problem with your unit test is this:
private TestEntities db = new TestEntities();
Your controller is tightly coupled to a dependency. Unless you have proper mocking set up within that dependency which isn't shown here, then your unit test will also be tightly coupled to that dependency.
Abstracting that dependency behind an interface and using dependency injection to de-couple your controller is highly recommended. That way your unit tests can supply a mock dependency with known, predictable behavior.
the code bellow run verry good for me :
var result = controller.Test(expectedArg) as JsonResult<MyClass>;
Assert.AreEqual(expectedResult, result.Content);

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 to setup Moq for repository

I have method
public IEnumerable<string> LoadCountries()
{
try
{
return GetAll().GetCountries();
}
catch (Exception)
{
return null;
}
}
GetAll() method load data from sql server but I don't need it in test
So i changed database on IEnumerable customers. I wanna test it
Mock<ICustomersRepository> mock = new Mock<ICustomersRepository>();
mock.Setup(m => m.GetAll()).Returns(customers.AsQueryable()); //change data
IEnumerable<string> countries = mock.Object.LoadCountries();
Assert.AreEqual(countries.Count(), 6); //expect 6 countries
But in this test countries.Count() == 0;
Sure I can modify Mock Setup and add
mock.Setup(m => m.LoadCountries()).Returns(customers.AsQueryable().GetCountries());
But I don't want to do it, because other functions that i want to test are much bigger.
Is anyone know how can set GetAll() function to return my test array, even if GetAll() implements inside test class?
I just try to set
mock.CallBase = true;
mock.Setup(m => m.LoadCountries()).CallBase();
but i just see exception
System.NotImplementedException: This is a DynamicProxy2 error:
The interceptor attempted to 'Proceed' for method
'System.Collections.Generic.IEnumerable`1[System.String] LoadCountries()' which has no target.
When calling method without target there is no implementation to 'proceed' to and
it is the responsibility of the interceptor to mimic the implementation (set return
value, out arguments etc).
You are creating dymic proxy class which implements ICustomersRepository interface. Then you are exercising this generated proxy:
Mock<ICustomersRepository> mock = new Mock<ICustomersRepository>();
IEnumerable<string> countries = mock.Object.LoadCountries();
That is not very good idea. What do you verify with this test? Proxy generation? Proxy will not be used by your real code. You should use mocks to provide mocked dependencies for testing of real classes which are used by your application.
Actually I would not test that LoadCountries() calls GetAll() internally. Because this is a details of implementation, and that is not a business requirement for customers repository. I would write some acceptance/integration tests to verify that with given customers correct countries are returned.
UPDATE: Thus your GetCountries() filter is an extension, then you don't need to involve repository in its testing. Thats a simple static class, which can be tested on its own. BUT your test without interaction with database also will not be very valuable, because your extension composes query to datasource, which will be translated by query provider. I'll give you an example. If you have local method call (or method which canot be translated by your query provider):
public static class Extensions
{
public static IQueryable<string> GetCountries(this IQueryable<Customer> q)
{
return q.GroupBy(c => c.Country).Select(x => LocalMethod(x.Key));
}
private static string LocalMethod(string country)
{
return country.ToUpper();
}
}
Then following unit test will pass when you work with objects in-memory:
List<Customer> customers = new List<Customer> {
new Customer { Country = "USA" },
new Customer { Country = "Spain" }
};
var countries = Extensions.GetCountries(customers.AsQueryable());
Assert.AreEqual(countries.Count(), 2);
But when you'll run your application which queries SQL database with Entity Framework, then EF will fail to translate this filter into SQL.
But if you are trying to tests your repository and your LoadCountries is in your Repository layer, then you shouldn´t mock your repo.
you can´t use a repository method on a mock object ;) atleast without specifying some Return()
If you mock your repo is because you don´t want to connect to the database for the testa dn you want to retrieve mock data using for example:
List<Country> myList = //Fill your list with countries
repo.Setup(x => x.LoadCountries).Return(myList);
And then, use some other part to use this mock data.
But as I said, if you are trying to tests your repository, you shouldn´t mock it.
You mock your repository when you are trying to for example, tests some business part, and then you need some fake data from the database, the, mock the repo, and get you fake data ;)
If is this case, then:
Mock<ICustomersRepository> mock = new Mock<ICustomersRepository>();
mock.Setup(x => x.LoadCountries).Return(myList);
then for example, if from your business layer you ask in the constructor the ICustomersRepository, then you can create a instance f the business layer and pass this mock repo.
MyService service = new MyService(mock.Object);
service.LoadAll();
And if this LoadAll() use LoadCountries, then when this LoadAll call to LoadCountries it will get your mock data of countries!
I hope this helps!

Categories

Resources