FakeItEasy to test domain services + UnitOfWork - c#

I started doing some experimentation with unit testing so that we can include them in our domain layer. However i dont know if I'm following the right path, thus i'm going to explain what i'm currently doing to see if i'm on the right track. Basically the architecture is like the following there is Domain Layer containing domain models and domain services (ex. User class and UserService class). Then Domain layer communicates with the DAL which implements the Generic Repository pattern together with the Unit of Work. Each domain service class in it's constructor accepts an IUnitOfWork interface, like the following:
public class UserService: IUserService
{
private readonly IUnitOfWork _unitOfWork;
public UserService(IUnitOfWork unitOfwork)
{
this._unitOfWork = unitOfwork;
}
}
In order to creat the unit tests, i decided to go with FakeItEasy framework. So in a UserServiceTest class i did the following:-
private IUserService _userService;
private const int userID = 2013;
[TestInitialize]
public void Initialize()
{
_userService = A.Fake<IUserService>();
A.CallTo(() => _userService.GetUserById(userID)).Returns(new User
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
}
[TestMethod]
public void GetUserByID()
{
var user = _userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
When I run the tests, they pass. Is it the correct way of implementing unit tests? Before I was trying a different approach however FakeItEasy was failing with a ProxyGenerator exception. What i was doing is this:-
[TestInitialize]
public void Initialize()
{
_unitOfWork = A.Fake<IUnitOfWork>();
A.CallTo(() => _unitOfWork.UserRepository.FindById(userID)).Returns(new UserDto
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
AutoMapper.Mapper.CreateMap<UserDto, User();
}
[TestMethod]
public void GetUserByID()
{
var userService = new UserService(_unitOfWork);
var user = userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
And this was throwing the below exception:-
Result Message:
Initialization method Initialize threw exception. System.ArgumentNullException: System.ArgumentNullException: Value cannot be null.
Parameter name: callTarget.
Result StackTrace:
at FakeItEasy.Creation.ProxyGeneratorSelector.MethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget, String& failReason)
at FakeItEasy.Configuration.DefaultInterceptionAsserter.AssertThatMethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget)
at FakeItEasy.Configuration.FakeConfigurationManager.AssertThatMemberCanBeIntercepted(LambdaExpression callSpecification)
at FakeItEasy.Configuration.FakeConfigurationManager.CallTo[T](Expression`1 callSpecification)
at FakeItEasy.A.CallTo[T](Expression`1 callSpecification)
Any feedback would be greatly appreciated. Thanks!

I think your original (second, in the question) test was failing because _unitOfWork.UserRepository is coming back as null in Initialize. Normally FakeItEasy will create an fake object when chained properties are used, but I'm guessing (I have to guess because I don't know anything about the type of UserRepository) that UserRepository's type is not fakeable. In that case, you'd get a null back from _unitOfWork.UserRepository.
Let me jump back to your second test (which was first in your question), then we'll return to what I think you might want to do here.
Looking at your test,
var user = _userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
I see a flaw. You're invoking a method on _userService directly, but _userService is a fake object, so the test doesn't actually involve any of the production code. It's really only exercising FakeItEasy.
I think what we want is sort of a blended approach - something that will exercise the code in a real UserService, without worrying about UserRepository. Maybe something similar to (and I'm not using a compiler here, and don't know what methods are on IUnitOfWork so take this with a grain of salt)
[TestInitialize]
public void Initialize()
{
_unitOfWork = A.Fake<IUnitOfWork>();
A.CallTo(() => _unitOfWork.GetUserById(userID))
.Returns(new User
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
}
[TestMethod]
public void GetUserByID()
{
var userService = new UserService(_unitOfWork);
var user = userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
Or, if there's nothing useful on IUnitOfWork except for UserRepository, then I think the next step would be to investigate why the type of UserRepository wasn't fakeable (if my guess was right) - is it sealed? Does it lack appropriate and accessible constructors?

Related

Mocking StandardKernal Interface with Ninject

I'm working on adding unit tests to some legacy ASP code with Moq and the Ninject.MockingKernal.
public class BaseController : Controller
{
private IAuthenticationManager authenticationManager;
public ILog log;
public BaseController()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
log = kernel.Get<ILog>();
}
}
The Log Interface:
public interface ILog
{
AuditTrail Create(AuditAction action, string description = null);
AuditTrail Create(AuditAction action, long reservationId, string description = null);
AuditTrail Create(IUser user, AuditAction action);
AuditTrail Create(IUser user, AuditAction action, string description = null);
AuditTrail Create(IUser user, AuditAction action, long reservationId, string description = null);
}
I'm trying to mock the log instance that is set up from the kernel. This log is inherited by other controllers and is not injected. I want to be able to return a mock object when it's requested, much like I would do in other cases (such as returning a mock DatabaseContext from a factory).
I've looked at this How to do Setup of mocks with Ninject's MockingKernel (moq) and the GitHub example: https://github.com/ninject/Ninject.MockingKernel/wiki/Examples, as well as many others.
From what I've gathered, I need to do something along these lines:
mockingKernal = new MoqMockingKernel();
mockingKernal.Bind<ILog>().To<Logging.Log>();
var foo = mockingKernal.GetMock<ILog>();
foo.Setup(x => x.Create(It.IsAny<AuditAction>(), It.IsAny<long>(), It.IsAny<string>()));
However, if I run this, I get an error System.ArgumentException: Object instance was not created by Moq. From what I can find online, this is caused by the class having a parameter in the constructor, but in this case, the Log class does not.
Am I approaching this in the correct way? And if I am, what am I doing wrong? Any help would be greatly appreciated
The above approach/design is going to cause all manner of head aches to maintain/test as the controller is tightly coupled to the kernel (IoC container) which basically does not allow one to be able to easily mock/replace it for testing.
Also note that the examples linked in question all have in common the ability to explicitly inject the dependencies into their subjects under test.
The above is basically using the kernel as a service locator.
Trying to put lipstick on that code may change its appearance but does nothing about the smell.
Ideally the design should be following the explicit dependency principle.
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
public class BaseController : Controller {
private IAuthenticationManager authenticationManager;
public ILog log;
public BaseController(ILog log, IAuthenticationManager authenticationManager) {
this.log = log;
this.authenticationManager = authenticationManager;
}
}
which would allow the dependencies to be mocked/faked/stubbed and injected into their dependents.
//Arrange
var logger = new Mock<ILog>();
logger
.Setup(_ => _.Create(It.IsAny<AuditAction>(), It.IsAny<long>(), It.IsAny<string>()))
.Return(new AuditTrail);
var controller = new BaseController(logger.Object, null);
//Act
//...
One should not be calling the container directly within classes but rather configure it at the composition root.
I suggest reviewing the current design and refactoring accordingly.

How to use Moq to mock up the StackExchange.Redis ConnectionMultiplexer class?

I am working to mock up behaviors related to the StackExchange.Redis library, but can't figure out how to properly mock the sealed classes it uses. A specific example is in my calling code I'm doing something like this:
var cachable = command as IRedisCacheable;
if (_cache.Multiplexer.IsConnected == false)
{
_logger.Debug("Not using the cache because the connection is not available");
cacheAvailable = false;
}
else if (cachable == null)
{
The key line in there is _cache.Multiplexer.IsConnected where I'm checking to make sure I have a valid connection before using the cache. So in my tests I want to mock up this behavior with something like this:
_mockCache = new Mock<IDatabase>();
_mockCache.Setup(cache => cache.Multiplexer.IsConnected).Returns(false);
However, while that code compiles just fine, I get this error when running the test:
I have also tried mocking the multiplexer class itself, and providing that to my mocked cache, but I run into the fact the multiplexer class is sealed:
_mockCache = new Mock<IDatabase>();
var mockMultiplexer = new Mock<ConnectionMultiplexer>();
mockMultiplexer.Setup(c => c.IsConnected).Returns(false);
_mockCache.Setup(cache => cache.Multiplexer).Returns(mockMultiplexer.Object);
...but that results in this error:
Ultimately I want to control whether that property is true or false in my tests, so is there a correct way to mock up something like this?
Use the interface IConnectionMultiplexer instead of the concrete class ConnectionMultiplexer in your own class.
public interface ICacheable
{
void DoYourJob();
}
public sealed class RedisCacheHandler : ICacheable
{
private readonly IConnectionMultiplexer multiplexer;
public RedisCacheHandler(IConnectionMultiplexer multiplexer)
{
this.multiplexer = multiplexer;
}
public void DoYourJob()
{
var database = multiplexer.GetDatabase(1);
// your code
}
}
Then you could easily mock and test it:
// Arrange
var mockMultiplexer = new Mock<IConnectionMultiplexer>();
mockMultiplexer.Setup(_ => _.IsConnected).Returns(false);
var mockDatabase = new Mock<IDatabase>();
mockMultiplexer
.Setup(_ => _.GetDatabase(It.IsAny<int>(), It.IsAny<object>()))
.Returns(mockDatabase.Object);
var cacheHandler = new RedisCacheHandler(mockMultiplexer.Object);
// Act
cacheHandler.DoYourJob();
// Assert
// your tests
The best approach in my opinion is to wrap all of your Redis interaction in your own class and interface. Something like CacheHandler : ICacheHandler and ICacheHandler. All of your code would only ever speak to ICacheHandler.
This way, you eliminate a hard dependency on Redis (you can swap out the implementation of ICacheHandler as you please). You can also mock all interaction with your caching layer because it's programmed against the interface.
You should not test StackExchange.Redis directly - it is not code you've written.
Not included in the above answer is the more detailed Setup of the mockDatabase instance. I struggled a little bit finding a working example of something as simple as mocking the IDatabase StringGet method (e.g., handling of optional parameters, using RedisKey vs string, using RedisValue vs string, etc.), so thought I would share. Here is what worked for me.
This test setup:
var expected = "blah";
RedisValue expectedValue = expected;
mockDatabase.Setup(db => db.StringGet(It.IsAny<RedisKey>(), It.IsAny<CommandFlags>()))
.Returns(expectedValue);
To affect what is returned by this tested method call:
var redisValue = _connectionMultiplexer.GetDatabase().StringGet(key);
I have solved this problem by using a connection provider class to create the instance of the ConnectionMultiplexer. The connection provider class can simply be injected into your cache service. The benefit of this approach is that the connection provider is the only code not tested (basically a single line of someone else's code) and your cache service can be tested by mocking the injected interfaces as normal.
In the code below my cache service can be tested and only the connection provider class needs to be excluded from code coverage.
public interface IElastiCacheService
{
Task<string> GetAsync(string key);
Task SetAsync(string key, string value, TimeSpan expiry);
}
public class ElastiCacheService : IElastiCacheService
{
private readonly ElastiCacheConfig _config;
private readonly IConnectionMultiplexer _connection = null;
public ElastiCacheService(
IOptions<ElastiCacheConfig> options,
IElastiCacheConnectionProvider connectionProvider)
{
_config = options.Value;
_connection = connectionProvider.GetConnection(_config.FullAddress);
}
public async Task<string> GetAsync(string key)
{
var value = await _connection.GetDatabase().StringGetAsync(key, CommandFlags.PreferReplica);
return value.IsNullOrEmpty ? null : value.ToString();
}
public Task SetAsync(string key, string value, TimeSpan expiry) =>
_connection.GetDatabase().StringSetAsync(key, value, expiry);
}
public interface IElastiCacheConnectionProvider
{
IConnectionMultiplexer GetConnection(string endPoint);
}
[ExcludeFromCodeCoverage]
public class ElastiCacheConnectionProvider : IElastiCacheConnectionProvider
{
public IConnectionMultiplexer GetConnection(string endPoint) =>
ConnectionMultiplexer.Connect(endPoint);
}

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.

Proper use of MOQ in a Unit Test

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.

Unit testing with Mocks. Test behaviour not implementation

I always had a problem when unit testing classes that calls other classes, for example I have a class that creates a new user from a phone-number then saves it to the database and sends a SMS to the number provided.
Like the code provided below.
public class UserRegistrationProcess : IUserRegistration
{
private readonly IRepository _repository;
private readonly ISmsService _smsService;
public UserRegistrationProcess(IRepository repository, ISmsService smsService)
{
_repository = repository;
_smsService = smsService;
}
public void Register(string phone)
{
var user = new User(phone);
_repository.Save(user);
_smsService.Send(phone, "Welcome", "Message!");
}
}
It is a really simple class but how would you go about and test it?
At the moment im using Mocks but I dont really like it
[Test]
public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase()
{
var repository = new Mock<IRepository>();
var smsService = new Mock<ISmsService>();
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
var phone = "07012345678";
userRegistration.Register(phone);
repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once());
}
[Test]
public void WhenRegistreringANewUser_ItWillSendANewSms()
{
var repository = new Mock<IRepository>();
var smsService = new Mock<ISmsService>();
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
var phone = "07012345678";
userRegistration.Register(phone);
smsService.Verify(x => x.Send(phone, It.IsAny<string>(), It.IsAny<string>()), Times.Once());
}
It feels like I am testing the wrong thing here?
Any thoughts on how to make this better?
Refactoring the mocks out in the way that #Serghei suggests is good.
I also see that the name of the behaviour isn't actually describing the behaviour. I like to use the word "should", as in, "My class should do some stuff".
Your class shouldn't send the user to the database when it's registering a user. It should ask the repository to save the user. That's all. It doesn't know whether the repository sends it to the database, keeps it in memory or nukes it from orbit. It's not your class's responsibility.
By phrasing the behaviour this way, you can explicitly show - and help others understand - where the scope of your class's responsibility ends.
If you rename your method something like WhenRegisteringANewUser_AsksRepositoryToSaveIt() that might make the example you've given feel more natural.
In your case don't need to write
repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once());
because this method doesn't return a value
you can write
repository.VerifyAll();
Also for smsService it's a good way to use Moq.
look at after some refactor
Mock<IRepository<>> repository;
private Mock<ISmsService> smsService;
const string phone = "0768524440";
[SetUp]
public void SetUp()
{
repository = new Mock<IRepository<>>();
smsService = new Mock<ISmsService>();
}
[Test]
public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase()
{
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
userRegistration.Register(phone);
repository.VerifyAll();
smsService.VerifyAll();
}

Categories

Resources