I have a problem with unit testing. I have a standart Reprository and UnitOfWork pattern. For example, I have a UnitOfWork class:
public class UnitOfWork : IDisposable
{
private readonly MyDbContext _context;
... repositories
private IMyEntityRepository _myEntityRepository;
...
}
UnitOfWok used in another part of program witch make some special operations with entities. For example, there is a method, whitch use UnitOfWork:
public IEnumerable<MyClass> MyMethod()
{
using (_unitOfWork = new UnitOfWork())
{
var myEntities= _unitOfWork.MyEntityRepository.Get();
var result = ... some logic to convert myEntities collection to IEnumerable<MyClass>
return result;
}
}
My question is how to write unit tests for MyMethod if there is consruction using(_unitOfWork = new UnitOfWork)? How could I use fake UnitOfWork with Fake context in that case? Thanks for any advice.
To make your classes more fake-able and testable I would suggest abstracting your UnitOfWork and Repositories if possible and then use a factory to inject them into the classes that depend on them.
public interface IUnitOfWork : IDisposable {
... repositories
IMyEntityRepository MyEntityRepository;
...
}
And your UnitOfWork will derive from that interface
public class UnitOfWork : IUnitOfWork {...}
IUnitOfWorkFactory
public interface IUnitOfWorkFactory {
IUnitOfWork Create();
}
With that, a dependent class can then look like this
public class MyDependentClass {
private readonly IUnitOfWorkFactory unitOfWorkFactory;
public MyDependentClass (IUnitOfWorkFactory unitOfWorkFactory) {
this.unitOfWorkFactory = unitOfWorkFactory;
}
public IEnumerable<MyClass> MyMethod() {
using (var _unitOfWork = unitOfWorkFactory.Create()) {
var myEntities= _unitOfWork.MyEntityRepository.Get();
var result = ... some logic to convert myEntities collection to IEnumerable<MyClass>
return result;
}
}
}
Now you can mock/fake your UnitOfWork and Repositories with no need to fake the Context.
Lets say you want to test/verify that the UOW is actually disposed of after calling MyMethod
(I'm using Moq and FluentAssert for demonstrative purposes)
You can construct a test as follows:
[TestMethod]
public void UOW_Should_Be_Disposed() {
//Assert
var fake_entities = Enumerable.Range(1, 10).Select(i => new MyEntity());
var mockRepository = new Mock<IMyEntityRepository>();
mockRepository.Setup(m => m.Get()).Returns(fake_entities);
var mockUOW = new Mock<IUnitOfWork>();
mockUOW.Setup(m => m.MyEntityRepository).Returns(mockRepository.Object);
var mockFactory = new Mock<IUnitOfWorkFactory>();
mockFactory.Setup(m => m.Create()).Returns(mockUOW.Object);
//Act
var sut = new MyDependentClass(mockFactory.Object);
var output = sut.MyMethod().ToList();
//Assert
output.Should().NotBeNull();
output.Should().HaveCount(10);
output.Should().ContainItemsAssignableTo<MyClass>();
mockUOW.Verify(m => m.Dispose());
}
The above shows how you can test everything easily using the frameworks mentioned.
Hope this helps
You have to inject a factory of UnitOfWork into the class that contains the MyMethod method via constructor injection like this:
public class MyClass
{
private readonly Func<UnitOfWork> unitOfWorkFactory;
public MyClass(Func<UnitOfWork> unitOfWorkFactory)
{
this.unitOfWorkFactory = unitOfWorkFactory;
}
public IEnumerable<MyClass> MyMethod()
{
using (unitOfWork = unitOfWorkFactory())
{
//..
}
}
}
Please note that the class takes a Func<UnitOfWork> instead of a UnitOfWork because I am assuming that you want each call to MyMethod to have a new instance of UnitOfWork.
In your tests, you create a fake UnitOfWork and then you can pass it to the MyClass instance like this:
var sut = new MyClass(() => fakeInstance);
You also need to make sure that UnitOfWork is fakeable. For example, since it is a concrete class, you need to make sure that the relevant methods are virtual. Another approach is to have an interface IUnitOfWork that UnitOfWork implements and that MyClass uses.
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