I am new to unit testing and I would like some help. I am using code first with repository pattern. I have a generic repository which contains generic CRUD operation called Generic Repository ( see blow )
public abstract class GenericRepository<T> where T : class
{
private HolidayDatabaseContext _dataContext;
private readonly IDbSet<T> _dbset;
protected GenericRepository(IDbFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = DataContext.Set<T>();
}
protected IDbFactory DatabaseFactory
{
get;
private set;
}
protected HolidayDatabaseContext DataContext
{
get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Update(T entity)
{
_dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual IEnumerable<T> Enumerable()
{
return _dbset.AsEnumerable<T>();
}
public virtual IQueryable<T> List()
{
return _dbset.AsQueryable<T>();
}
public virtual T GetSingleById(int id)
{
return _dbset.Find(id);
}
public void Save()
{
_dataContext.SaveChanges();
}
}
I have then inherited it into a User Repository and created some specific methods. see below
public class UserRepository : GenericRepository<User>, IUserRepository
{
public UserRepository(IDbFactory databaseFactory)
: base(databaseFactory) { }
public int HolidayEntitlement(int userId)
{
return HolidayEntitlement(userId, DateTime.Now);
}
public int HolidayEntitlement(int userId, DateTime dateTime)
{
//Get the User
var user = this.GetSingleById(userId);
//Work Total Entitlement
int entitlement = user.BaseHolidayEntitlement;
//Years in Service
entitlement += (dateTime - user.EmploymentStartDate).Days / 365;
return entitlement;
}
public int RemainingHolidayEntitlement(int userId)
{
return RemainingHolidayEntitlement(userId, DateTime.Now);
}
public int RemainingHolidayEntitlement(int userId, DateTime dateTime)
{
return int.MinValue;
}
}
I would like to Unit test HolidayEntitlement(int userId, DateTime dateTime) but i need to mock the GetSingleById part in the method
I have written this as a Test but it doesn't compile.
[TestMethod]
public void GetHolidayEntitlement25()
{
//How to write this Unit test
//Setup
var user = new User { AnnualHolidayIncrement = 1, BaseHolidayEntitlement = 25, EmploymentStartDate = new DateTime(2013, 1, 1),Id=1 };
Mock<UserRepository> mock = new Mock<UserRepository>();
mock.Setup(m => m.GetSingleById(1)).Returns(user);
Assert.AreEqual(25, mock.Object.HolidayEntitlement(1));
}
Any help would be appreciated
You seem to be saying that you only want to mock part of the interface. When you start encountering this sort of situation it suggests that you are mixing your concerns and probably doing something wrong somewhere.
In this instance your Repository is doing MUCH more than just CRUD and therefore has multiple responsibilities (it should only have one, lookup SOLID programming). You are performing Business logic in the repository and it should not live there! Anything other than simple CRUD operations should be moved out into the Business Logic Layer. I.e. your HolidayEntitlement
method calculates something by applying some logic and is therefore NOT a CRUD / repository operation!
So... What you should do is move the business logic bits out into a new class, say UserLogic
. Within the UserLogic
class you would use an injected IUserRepository
to communicate with your repository. In UserLogic
that is where you would put your HolidayEntitlement
method and it would make a call to IUserRepository.GetSingleById
. So, when you then test your UserLogic
class you would inject in your mock IUserRepository
that would have the stub version of GetSingleById
and then you will be back on the right track!
I hope that makes sense / helps?!
--ORIGINAL POST--
P.S. My original post stated that you should mock interfaces, not instances so this still applies and I will leave here for reference:
You should be mocking IUserRepository
NOT UserRepository
.
That is because UserRepository
is an implementation of IUserRepository
. You want to say that you are giving it a NEW implementation, i.e. your mock. At the moment you are using the ACTUAL class UserRepository
.
Mocking is generally used when you need to supply a fake dependency and in this case you appear to be trying to Mock the System Under Test (SUT) which doesn't really make sense - there's literally no point because your test is not actually telling you anything about the behaviour of UserRepository
; all you are doing is testing if you setup your Mock correctly which isn't very useful!
The test code you have given seems to indicate that you want to test UserRepository.HolidayEntitlement
.
I would be much more inclined to move functions like that out of your Repository class and into a separate business-logic type class. This way you can test the logic of calculating a user's holiday entitlement in total isolation which is a major principle of unit testing.
In order to test that this function does what it's supposed to do (i.e perform a calculation based on properties of a User
) you need to ensure that whatever User
instance is being operated on within that function is 100% isolated and under your control - either with a Mock or Fake (Stub) instance of User, in this case Mocks are an excellent choice because you only need to implement the parts of the dependency that your SUT is going to need.
So, what you could do is this:
Define an interface for User
public interface IUser
{
int BaseHolidayEntitlement{get;set;}
DateTime EmploymentStartDate {get;set;}
//other properties for a User here
}
Implement this on your User class
public class User:IUser
{
//implemement your properties here
public int BaseHolidayEntitlement{get;set;}
public DateTime EmploymentStartDate {get;set;}
//and so on
}
Create a class for User logic
public class UserRules
{
public int GetHolidayEntitlement(IUser user,DateTime dateTime)
{
//perform your logic here and return the result
}
}
Now your test becomes much simpler and doesn't even need the repository
[TestMethod]
public void GetHolidayEntitlement_WithBase25_Returns25()
{
//Arrange
var user = new Mock<IUser>();
//setup known, controlled property values on the mock:
user.SetupGet(u=>u.BaseHolidayEntitlement).Returns(25);
user.SetupGet(u=>u.EmploymentStartDate).Returns(new DateTime(2013,1,1));
var sut = new UserRules();
int expected = 25;
//Act
int actual = sut.GetHolidayEntitlement(user.Object,DateTime.UtcNow);
//Assert
Assert.AreEqual(expected,actual,"GetHolidayEntitlement isn't working right...");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With