Pregunta

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
    }
}
¿Fue útil?

Solución

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.

Otros consejos

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).

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top