Reputation: 910
I have a DataService class like below
public class LessonDataService
{
IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork();
public Lesson FindById(int id)
{
try
{
return unitOfWork.Lessons.FindById(id);
}
catch (Exception ex)
{
throw exception;
}
}
}
As you can see the UnitOfWork is constructed inside of the DataService class. I also don't want the pass the UnitOfWork through constructor, I don't want the UI code to bother with UnitOfWork I just want it to call the DataService class and let it do the rest. Any ideas?
Upvotes: 2
Views: 2802
Reputation: 910
What I settled for is that I make an Internal constructor for the DataService
and make it visible to unit tests project using InternalsVisibleToAttribute
so that I can override the factory and inject and Mock UnitOfWork.
Upvotes: 0
Reputation: 247018
How to unit test code that depends on a Factory
Short Answer: You Don't.
Abstract Factories are a code smell
Tightly coupled code is difficult to test. (but not impossible).
Refactor your code for explicit dependency via constructor injection. (avoid service locator anti-pattern)
public class LessonDataService : ILessonDataService {
private readonly IUnitOfWork unitOfWork;
public LessonDataService(IUnitOfWork unitOfWork) {
this.unitOfWork = unitOfWork;
}
public Lesson FindById(int id) {
try {
return unitOfWork.Lessons.FindById(id);
} catch (Exception ex) {
throw exception;
}
}
}
I don't want the UI code to bother with UnitOfWork I just want it to call the DataService class and let it do the rest.
Then abstract the service, inject that into the UI and let it do the rest. The UI should not be directly concerned with the UOW.
public interface ILessonDataService {
Lesson FindById(int id);
}
By refactoring to depend on explicit abstractions, the code is now more flexible and can be tested in isolation with minimal negative effects.
[TestMethod]
public void DataService_Should_Get_Lesson() {
//Arrange
var id = 1;
var lesson = new Lesson {
Id = id,
//...code removed for brevity
};
var mock = new Mock<IUnitOfWork>();
mock.Setup(_ => _.Lessons.FindById(id)).Returns(lesson);
var sut = new LessonDataService(mock.Object);
//Act
var actual = sut.FindById(id);
//Assert
lession.Should().BeEquivalentTo(actual);
}
In production code the current factory could still be registered with the DI container in the composition root, yet still keeps the code decoupled.
For example (in .Net Core)
services.AddTransient<IUnitOfWork>(_ => UnitOfWorkFactory.CreateUnitOfWork());
services.AddTransient<ILessonDataService, LessonDataService>();
Upvotes: 6
Reputation: 3841
Use a Mocking framework. Unit tests are meant to test the piece of code not the branches or connected classes. Use mock framework like Mockito or easymock, mock the UnitOfWorkFactory
and create your own output for unitOfWork.Lessons.FindById(id)
. Remember to test all possibilities. Use this link to learn more about Mockito.
Upvotes: 0