Reputation: 2492
So here is a simplified version of my classes. I have two classes that implement a service interface. One is my actual implementation and one is my mock.
I need to create X number of new instances of this service class inside of my Worker class.
How do I tell my Worker class which IService I want to use?
Is mocking up the Worker class the only route to go? Is there a better route?
Edit: So after reading some of the responses, I feel that I did not accurately convey my situation. I oversimplified to the point of hindering. Anyways I added more code that may help explain what I have going on.
I changed the original Worker
class to be Manager
and have a child list of Workers
. The list of workers is created from the Manager
class and I construct them using the IService
which I would like to pass a Concrete OR Mock implementation. I then will kick off the Workers to do something involving IService
and a variable that I provide it. (In this case it's just an integer, but in real life it's a class).
public interface IService
{
int a { get; set; }
}
public class Concrete : IService
{
public int a { get; set; }
float x;
public Concrete(int A)
{
a = A;
x = 0.500F;
}
}
public class Mock : IService
{
public int a { get; set; }
float x;
public Mock(int A)
{
a = A;
x = 0.750F;
}
}
public class Manager
{
List<Worker> Workers = new List<Worker>();
void CreateList()
{
for (int i = 1; i <= 3; i++)
{
Worker w = new Worker(new IService(i)); //<-- Need help here!
theList.Add(w);
}
KickOffWorkesAsync();
}
void KickOffWorkesAsync()
{
// process the workers async
}
}
public class Worker
{
IService _iService;
public Worker(IService _iSer)
{
_iService = _iSer;
}
void DoSomething()
{
//do work with _iService
}
}
Upvotes: 1
Views: 417
Reputation: 150
Another alternative is to give the worker a factory method that will create the service:
public class Worker
{
private Func<int, IService> createService;
public Worker(Func<int, IService> createService)
{
this.createService = createService;
}
Then the worker can do:
void DoSomething()
{
var theList = new List<IService>();
for (int i = 1; i <= 3; i++)
{
IService s = createService(i); // Invoke the provided factory method
theList.Add(s);
}
// do something with the list...
}
and the unit test can create the worker like so:
public void SomeTestMethod()
{
var worker = new Worker(CreateMockService);
}
private IService CreateMockService(int arg)
{
return new Mock(arg);
}
The production code would provide a factory method creating real services.
Upvotes: 2
Reputation: 5750
To answer your question as simple as I can.
void DoSomething()
{
var theList = new List<IService>();
for (int i = 1; i <= 3; i++)
{
//use this
IService s = new Concrete(i);
//or this
//IService s = new new Mock(i);
theList.Add(s);
}
// do something with the list...
}
But the better way is to use some type of dependency injection or factory (like the other answer explains), so you could specify either in a config file, or in your app startup, what IService
you want to use.
Upvotes: 0
Reputation: 4626
This is where Dependency Injection comes in handy. You'll need to design your classes to get their dependencies from outside instead of creating them yourself.
Something like:
public class Worker
{
public Worker(IService service)
{
this.service = service;
}
public void DoSomething()
{
DoSomethingWith(service);
}
}
Then in your tests, you could create a Worker
instance injected with a mock service, whereas in production code you'll use a real service.
When using Dependency Injection, it helps to use a DI Container (also sometimes called an Inversion of Control Container), to wire up the dependent services correctly instead of manually creating the dependency graph. Some common DI Containers for .NET include Ninject, StructureMap, Castle Windsor, and Microsoft's Unity.
If you've never used DI before, it's quite a paradigm shift, but it's essentially a simple change that can do wonders to the design of your code (for many reasons, not just for testing).
Upvotes: 2