Sisyphus
Sisyphus

Reputation: 910

How to unit test code that depends on a Factory

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

Answers (3)

Sisyphus
Sisyphus

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

Nkosi
Nkosi

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

Arun
Arun

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

Related Questions