Proper use of MOQ in a Unit Test - c#

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.

Related

How to create unit test for a service class?

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 ?

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 to implement FIND method of EF in Unit Test?

I have a Web API 2.0 project that I am unit testing. My controllers have a Unit of Work. The Unit of Work contains numerous Repositories for various DbSets. I have a Unity container in the Web API and I am using Moq in the test project. Within the various repositories, I use the Find method of Entity Framework to locate an entity based on it's key. Additionally, I am using Entity Framework 6.0.
Here is an very general example of the Unit of Work:
public class UnitOfWork
{
private IUnityContainer _container;
public IUnityContainer Container
{
get
{
return _container ?? UnityConfig.GetConfiguredContainer();
}
}
private ApplicationDbContext _context;
public ApplicationDbContext Context
{
get { _context ?? Container.Resolve<ApplicationDbContext>(); }
}
private GenericRepository<ExampleModel> _exampleModelRepository;
public GenericRepository<ExampleModel> ExampleModelRepository
{
get { _exampleModelRepository ??
Container.Resolve<GenericRepository<ExampleModel>>(); }
}
//Numerous other repositories and some additional methods for saving
}
The problem I am running into is that I use the Find method for some of my LINQ queries in the repositories. Based on this article, MSDN: Testing with your own test doubles (EF6 onwards), I have to create a TestDbSet<ExampleModel> to test the Find method. I was thinking about customizing the code to something like this:
namespace TestingDemo
{
class TestDbSet : TestDbSet<TEntity>
{
public override TEntity Find(params object[] keyValues)
{
var id = (string)keyValues.Single();
return this.SingleOrDefault(b => b.Id == id);
}
}
}
I figured I would have to customize my code so that TEntity is a type of some base class that has an Id property. That's my theory, but I'm not sure this is the best way to handle this.
So I have two questions. Is the approach listed above valid? If not, what would be a better approach for overriding the Find method in the DbSet with the SingleOrDefault method? Also, this approach only really works if their is only one primary key. What if my model has a compound key of different types? I would assume I would have to handle those individually. Okay, that was three questions?
To expand on my comment earlier, I'll start with my proposed solution, and then explain why.
Your problem is this: your repositories have a dependency on DbSet<T>. You are unable to test your repositories effectively because they depend on DbSet<T>.Find(int[]), so you have decided to substitute your own variant of DbSet<T> called TestDbSet<T>. This is unnecessary; DbSet<T> implements IDbSet<T>. Using Moq, we can very cleanly create a stub implementation of this interface that returns a hard coded value.
class MyRepository
{
public MyRepository(IDbSet<MyType> dbSet)
{
this.dbSet = dbSet;
}
MyType FindEntity(int id)
{
return this.dbSet.Find(id);
}
}
By switching the dependency from DbSet<T> to IDbSet<T>, the test now looks like this:
public void MyRepository_FindEntity_ReturnsExpectedEntity()
{
var id = 5;
var expectedEntity = new MyType();
var dbSet = Mock.Of<IDbSet<MyType>>(set => set.Find(It.is<int>(id)) === expectedEntity));
var repository = new MyRepository(dbSet);
var result = repository.FindEntity(id);
Assert.AreSame(expectedEntity, result);
}
There - a clean test that doesn't expose any implementation details or deal with nasty mocking of concrete classes and lets you substitute out your own version of IDbSet<MyType>.
On a side note, if you find yourself testing DbContext - don't. If you have to do that, your DbContext is too far up the stack and it will hurt if you ever try and move away from Entity Framework. Create an interface that exposes the functionality you need from DbContext and use that instead.
Note: I used Moq above. You can use any mocking framework, I just prefer Moq.
If your model has a compound key (or has the capability to have different types of keys), then things get a bit trickier. The way to solve that is to introduce your own interface. This interface should be consumed by your repositories, and the implementation should be an adapter to transform the key from your composite type into something that EF can deal with. You'd probably go with something like this:
interface IGenericDbSet<TKeyType, TObjectType>
{
TObjectType Find(TKeyType keyType);
}
This would then translate under the hood in an implementation to something like:
class GenericDbSet<TKeyType,TObjectType>
{
GenericDbSet(IDbSet<TObjectType> dbset)
{
this.dbset = dbset;
}
TObjectType Find(TKeyType key)
{
// TODO: Convert key into something a regular dbset can understand
return this.dbset(key);
}
}
I realise this is an old question, but after coming up against this issue myself when mocking data for unit tests I wrote this generic version of the 'Find' method that can be used in the TestDBSet implementation that is explained on msdn
Using this method means you dont have to create concrete types for each of your DbSets. One point to note is that this implementaion works if your entities have primary keys in one of the following forms (im sure you could modify to suite other forms easily):
'Id'
'ID'
'id'
classname +'id'
classname +'Id'
classname + 'ID'
public override T Find(params object[] keyValues)
{
ParameterExpression _ParamExp = Expression.Parameter(typeof(T), "a");
Expression _BodyExp = null;
Expression _Prop = null;
Expression _Cons = null;
PropertyInfo[] props = typeof(T).GetProperties();
var typeName = typeof(T).Name.ToLower() + "id";
var key = props.Where(p => (p.Name.ToLower().Equals("id")) || (p.Name.ToLower().Equals(typeName))).Single();
_Prop = Expression.Property(_ParamExp, key.Name);
_Cons = Expression.Constant(keyValues.Single(), key.PropertyType);
_BodyExp = Expression.Equal(_Prop, _Cons);
var _Lamba = Expression.Lambda<Func<T, Boolean>>(_BodyExp, new ParameterExpression[] { _ParamExp });
return this.SingleOrDefault(_Lamba);
}
Also from a performance point of view its not going to be as quick as the recommended method, but for my purposes its fine.
So based on the example, I did the following to be able to Unit Test my UnitOfWork.
Had to make sure my UnitOfWork was implementing IApplicationDbContext. (Also, when I say UnitOfWork, my controller's UnitOfWork is of type IUnitOfWork.)
I left all of the DbSet's in my IApplicationDbContext alone. I chose this pattern once I noticed IDbSet didn't include RemoveRange and FindAsync, which I use throughout my code. Also, with EF6, the DbSet can be set to virtual and this was recommended in MSDN, so that made sense.
I followed the Creating the in-memory test doubles
example to create the TestDbContext and all the recommended classes (e.g. TestDbAsyncQueryProvider, TestDbAsyncEnumerable, TestDbAsyncEnumerator.) Here is the code:
public class TestContext : DbContext, IApplicationDbContext
{
public TestContext()
{
this.ExampleModels= new TestBaseClassDbSet<ExampleModel>();
//New up the rest of the TestBaseClassDbSet that are need for testing
//Created an internal method to load the data
_loadDbSets();
}
public virtual DbSet<ExampleModel> ExampleModels{ get; set; }
//....List of remaining DbSets
//Local property to see if the save method was called
public int SaveChangesCount { get; private set; }
//Override the SaveChanges method for testing
public override int SaveChanges()
{
this.SaveChangesCount++;
return 1;
}
//...Override more of the DbContext methods (e.g. SaveChangesAsync)
private void _loadDbSets()
{
_loadExampleModels();
}
private void _loadExampleModels()
{
//ExpectedGlobals is a static class of the expected models
//that should be returned for some calls (e.g. GetById)
this.ExampleModels.Add(ExpectedGlobal.Expected_ExampleModel);
}
}
As I mentioned in my post, I needed to implement the FindAsync method, so I added a class called TestBaseClassDbSet, which is an alteration of the TestDbSet class in the example. Here is the modification:
//BaseModel is a class that has a key called Id that is of type string
public class TestBaseClassDbSet<TEntity> :
DbSet<TEntity>
, IQueryable, IEnumerable<TEntity>
, IDbAsyncEnumerable<TEntity>
where TEntity : BaseModel
{
//....copied all the code from the TestDbSet class that was provided
//Added the missing functions
public override TEntity Find(params object[] keyValues)
{
var id = (string)keyValues.Single();
return this.SingleOrDefault(b => b.Id == id);
}
public override Task<TEntity> FindAsync(params object[] keyValues)
{
var id = (string)keyValues.Single();
return this.SingleOrDefaultAsync(b => b.Id == id);
}
}
Created an instance of TestContext and passed that into my Mock.
var context = new TestContext();
var userStore = new Mock<IUserStore>();
//ExpectedGlobal contains a static variable call Expected_User
//to be used as to populate the principle
// when mocking the HttpRequestContext
userStore
.Setup(m => m.FindByIdAsync(ExpectedGlobal.Expected_User.Id))
.Returns(Task.FromResult(ExpectedGlobal.Expected_User));
var mockUserManager = new Mock(userStore.Object);
var mockUnitOfWork =
new Mock(mockUserManager.Object, context)
{ CallBase = false };
I then inject the mockUnitOfWork into the controller, and voila. This implementation seems to be working perfect. That said, based on some feeds I have read online, it will probably be scrutinized by some developers, but I hope some others find this to be useful.

Unit Testing with DbContext mock through Service Layer

I'm a beginner at writing unit tests and I have a test I'm trying to get working. I'll start of by explaining what I'm trying to test.
I'm trying to test a method which saves messages in a Mvc 4 project. The method is called SaveMessage and is shown below.
namespace ChatProj.Service_Layer
{
public class UserService : IUserService
{
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
private IMessageRepository _messageRepository;
-> public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
The _messageRepository.Save in the SaveMessage method is implemented in my DAL layer MessageRepository and looks like this:
public void Save()
{
context.SaveChanges();
}
This way of saving will seem a bit overcomplicated, but I structured the project this way because I didn't want the service layer (IUserService & UserService) to handle operations that could & should (i think) be handled by the Data Access Layer (IMessageRepository & MessageRepository).
Now comes the tricky part. I've been trying to understand how I could unit test this. This is my try:
namespace ChatProj.Tests
{
[TestFixture]
class MessageRepositoryTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void SaveMessage_SaveWorking_VerifyUse()
{
//Arrange
var userServiceMock = new Mock<UserService>();
var message = new Message { MessageID = 0, Name = "Erland", MessageString = "Nunit Test", MessageDate = DateTime.Now };
var repositoryMock = new Mock<IMessageRepository>();
var contextMock = new Mock<MessageContext>();
MessageRepository messageRepository = new MessageRepository(contextMock.Object);
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
//Assert
repositoryMock.Verify(m => m.Save());
userServiceMock.Verify(m => m.SaveMessage(message));
}
}
I get this error: Imgur link , and I'm not quite sure how to solve it. I've tried looking at several other SO posts but I fail to make the test work.
So I'm wondering, how do I practically get my Unit Test to work?
You should setup your MessageContext properties to return fake data and don't make real Db call with SaveChanges method.
Right now it still tries to access a real DB.
But you can setup only virtual properties or if it will be an inteface.
So the best solution is to extract an interface from your MessageContext and inject it into repository. Then you can easily mock your IMessageContext interface and force it to return appropriate in-memory data.
Take a look at these two lines:
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
You're creating a userService instance, and then immediately saving your message. Now jump into the SaveMessage code.
public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
Ok, now you're adding stuff to messageContext, and then calling _messageRepository.Save(). But where are messageContext and _messageRepository instantiated?
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
You're creating them at instantiation. The mocks that you've created in your test aren't being used. Instead of creating instances of these objects in the constructor, you might consider passing them into the UserService constructor as arguments. Then, you can pass in mocked instances in your test.

MS Test for Void Methods

I have a void method, which i need to unit test, can some one please help me how to do it
[TestMethod()]
public void ProcessProductFeedTest()
{
// TODO: Initialize to an appropriate value
ProductDataServiceProvider target = new ProductDataServiceProvider();
target.ProcessProductFeed();
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
in the above code ProcessProductFeed() is a void method which gets some data from SQL server DB and publish to TIBCO, how can i write a unit test case for the same
Well, you should test that the data is published to TIBCO, basically.
For any method, your tests should either test that the value returned is correct if the primary purpose is to compute something, or that the appropriate side-effects have occurred if that's the primary purpose of the method. (You then test the error conditions as well, of course.)
Without knowing anything about either TIBCO or your architecture, I can't really comment on how you go about testing the publishing part. I would personally separate out the three stages of reading, processing and publishing - then each part can be tested in isolation from the others.
Abstract persistence and TIBCO communication from your class. E.g. you can use some repository interface for communication with SQL server :
public interface IProductsRepository
{
IEnumerable<Product> GetSomeProducts();
// other members
}
And some gateway for communcation with TIBCO (I named it Stock, but you should provide business specific names):
public interface IStockGateway
{
void DoSomethingWithProducts(IEnumerable<Product> products);
// other members
}
Then make your class depend on these abstractions. You will be able to mock them and verify class behavior:
public class ProductDataServiceProvider
{
private IProductsRepository _productRepository;
private IStockGateway _stockGateway;
// inject implementations
public ProductDataServiceProvider(
IProductRepository productRepository,
IStockGateway stockGateway)
{
_productRepository = productRepository;
_stockGateway = stockGateway;
}
public void ProcessProductFeed()
{
// use repository and gateway
}
}
Now, back to test. What are responsibilities of your provider - get some products from product repository (implementation of this repository will load products from SQL database) and pass them to gateway (implementation of gateway will publish products to TIBCO). Here is test which uses Moq library:
[TestMethod]
public void ShouldPassSomeProjectToStock()
{
// Arrange
var products = new List<Product>() { }; // create some products
var mockRepository = new Mock<IProductRepository>();
mockRepository.Setup(r => r.GetSomeProducts()).Returns(products);
var mockGateway = new Mock<IStockGateway>();
mockGateway.Setup(g => g.DoSomethingWithProducts(products));
var provider = new ProductDataServiceProvider(mockRepository.Object,
ockGateway.Object);
// Act
provider.ProcessProductFeed();
// Assert
mockRepository.VerifyAll(); // verify products retrieved from repository
mockGateway.VerifyAll(); // verify products passed to gateway
}

Categories

Resources