Reputation: 2405
I have a service and i want test without using the "real" repository, but a mock repository. the main program
ServiceManager service = new ServiceManager();
Customer c = new Customer();
//set customer properties
service.Save(c);
the service
public class ServiceManager
{
public bool Save(Customer customer)
{
Repository rep = new Repository();
bool res = rep.Save((customer));
return res;
}
}
in test, i don't want save really the customer. using mock, i can create the repository
var rep = new Mock<Repository>();
rep.Setup(x => x.Save(customer)).Returns(true);
but how can i call in test the service using this mock repository and not the real repository?
if possible i don't want create service like new ServiceManager(repository);
another way is use a factory of repository that return the mock if we are in test and the real repository when in real world, such as
public static class repositoryFactory
{
private static Repository mockRepository;
public static void setRepository(Repository rep){
mockRepository = rep;
}
public static Repository getRepository(){
if (mockRepository == null)
return new Repository();
else
return mockRepository;
}
}
in this case in test i use setRepository to save the mock. which is the best solutions adopted in general?
Upvotes: 1
Views: 300
Reputation: 101122
The classic way is to use Inversion of Control (that means that ServiceManager
is no longer in control of creating Repository
), commonly achieved by Dependency Injection (that means the dependency Repository
is "injected" into SericeManager
).
You seem to already know that, since you wrote
if possible i don't want create service like new ServiceManager(repository);
You can, to achieve this, use an optional argument in the constructor of ServiceManager
, like:
public class ServiceManager
{
private readonly IRepository rep;
public ServiceManager(IRepository rep=null)
{
_rep = rep ?? new Repository();
}
public bool Save(Customer customer)
{
bool res = _rep.Save((customer));
return res;
}
}
to be able to simply use new ServiceManager()
in your application and use new ServiceManager(repositoryMock)
in your tests.
However, if you use a IOC-Container (like e.g. StructureMap), injecting dependencies is plain easy: you can leave the creation of objects to the IOC-Container and keep your ServiceManager
and other classes "clean" of creating instances of dependend classes manually.
Upvotes: 1
Reputation: 107317
if possible i don't want create service like new ServiceManager(repository);
If this is an absolute requirement, you'll need to use heavy handed tools like Fakes / Moles
to mangle a moled repository into your ServiceManager
SUT.
However, since this is tagged moq
, if you do decouple your dependencies (e.g. via Setter constructor injection), then you can unit test and Mock
in isolation. Its a small overhead to make for testable code.
public class ServiceManager
{
private readonly Repository _repository;
public ServiceManager(Repository repository)
{
_repository = repository;
}
public bool Save(Customer customer)
{
bool res = _repository.Save((customer));
return res;
}
}
And your unit test will now be able to create the ServiceManager
(the SUT) and inject the Mocked repository.
And even better would be to abstract repository into an interface, IRepository
, and then reduce the dependency of ServiceManager
to Repository
to an interface. Your moq repo is then var rep = new Mock<IRepository>();
and the dependency becomes private readonly IRepository _repository;
.
Upvotes: 0