Reputation: 18684
I've run into a problem. I have created a solution that uses IoC. However, I have a fatal flaw - a primary DTO that I use (Data Transfer Object - so, a class that passes through the layers) contains, for example, a Person with Name, Surname, DateOfBirth, StatusId ... and a List of valid Statuses.
The statuses are populated when the Person class is created, and data comes from a reference data repository... this repository is a singleton and gets data from a cache (one it's got data from the database initially).
So,
Name string {get; set;}
Surname string {get; set;}
StatusId int {get; set;}
Statuses List<ReferenceItem> {get; set;} = ReferenceData.GetData(DataType.ClientStatus);
In my unit test, I end up with a dependency on the ReferenceData class, which is a singleton. Is there a way to inject a mock ReferenceData class somehow? Or is my design flawed, and I need to redesign my Person class?
Upvotes: 0
Views: 125
Reputation: 32445
As other pointed out for being able to test your code you should redesign it that code will be testable.
You are using DTO(Data Transfer Object) for passing data through different layers, I think, with this kind of responsibility those objects should have minimum dependencies on one of the layers.
In your case your DTO depend on static method or injected interface, or even worse on IoC container. Remove all of them and make your DTO to be object which responsibility is carrying data.
public class Person
{
public string Name{ get; set; }
public string Surname { get; set; }
public int StatusId { get; set; }
public List<ReferenceItem> Statuses { get; set; }
}
Then anywhere where you creating instance of Person you will have to inject IReferenceDataProvider
.
Or you can introduce a Factory abstraction for creating instances of Person
public interface IPersonFactory
{
Person Create(string name, string surname, int statusId);
}
And implementation
public class PersonFactory
{
private readonly IReferenceDataProvider _dataProvider;
public PersonFactory(IReferenceDataProvider dataProvider)
{
_dataProvider = dataProvider;
}
public Person Create(string name, string surname, int statusId)
{
return new Person
{
Name = name,
Surname = surname,
StatusId = statusId,
Statuses = _dataProvider.GetData(DataType.ClientStatus)
};
}
}
Upvotes: 1
Reputation: 2098
You have to redesign your class and use constructor injection. Follow this example (refered to yours):
class Person {
public string Name { get; set; }
public string Surname { get; set; }
public int StatusId { get; set; }
public List<ReferenceItem> Statuses { get; set; }
public Person(IReferenceDataProvider provider) {
Statuses = provider.GetData(DataType.ClientStatus);
}
}
Or you can use directly the IoC container to resolve your dependency inside the constructor:
...
public Person() {
var provider = IoC.Resolve<IReferenceDataProvider>();
Statuses = provider.GetData(DataType.ClientStatus);
}
...
Anyway you have to abstract your class reference and use interface instead. Hope this can help.
Upvotes: 2