views:

381

answers:

8

I have a class that I am trying to do unit tests on. The class is a WCF Service Class. (Making it a generics class is not my goal.)

I have a data access layer (DAL) type (called UserDAL) that is instantiated in many methods. To get these methods under test, I need to get this local variables mocked. (Each instance of UserDAL has method specific value in it, so changing it a class level variable would result in messy code, so I would rather not do that.)

What I am thinking would be nice is to overload the constructor and pass in a type to use in the local methods. The empty param constructor would still create a normal UserDAL, but the overloaded one would have a mock type that implements IUserDAL.

I am not sure of the syntax to say I want to pass in a type. Note that I am not trying to pass in a variable, but a type.

Example:

public class MyWCFClass: IMyWCFClass
{
    private TypeParam _myUserDALType;
    public MyWCFClass()
    {
        _myUserDALType = UserDAL;
    }
    public MyWCFClass(TypeParam myUserDALType)
    {
        _myUserDALType = myUserDALType;
    }

    //methods to use it
    public MyMethod()
    {
        IUserDAL userDAL = new _myUserDALType();
        //Call method in IUserDAL
        userDAL.CreateUser();
    }


    // Several similar methods that all need a different UserDAL go here
    .....
}

So, I don't know what kind of type TypeParam is (I made that up) or if this kind of think is even possible.

If you have a non generics solution that would be great.

+5  A: 

Use a Type, and use Activator.CreateInstance to instantiate it:

private Type _myUserDALType;

IUserDAL userDAL = Activator.CreateInstance(_myUserDALType) as IUserDAL;
itowlson
+2  A: 

If you want to pass in a type, you can use the Type object:

public class A
{
  public A(Type classType)
  {
    object myObject = Activator.CreateInstance(...classType...);
  }
}

public class B
{
...
}

public class C
{
  public static void main(string[] args)
  {
    A a = new A(typeof(B));
  }

}

Russell
+8  A: 

What you are really looking for is Dependency Injection, but you can do this by passing in a Type argument and then using Activator.CreateInstance(Type) to create the object when you need it.

As far as doing real DI (which will make doing this testing a lot easier), I know that Spring.Net works reasonable well.

Chris
+5  A: 

You mean Type, using Activator.CreateInstance to create instances:

public class MyWCFClass: IMyWCFClass
{
    private Type _myUserDALType;
    public MyWCFClass()
    {
        _myUserDALType = typeof(UserDAL);
    }
    public MyWCFClass(Type myUserDALType)
    {
        _myUserDALType = myUserDALType;
    }

    //methods to use it
    public void MyMethod()
    {
        IUserDAL userDAL = (IUserDAL) Activator.CreateInstance(_myUserDALType );
        //Call method in IUserDAL
        userDAL.CreateUser();
    }
}
Marc Gravell
Although this solution is exactly what Vaccano asked for I encourage the solution Chris and JS Bangs suggested: use InversionOfControl and a Container (Spring.Net, Ninject, Structuremaps, Unity, LinFu, you name it...) as well as ctor-injection. Also in the above solution there will be exceptions thrown during runtime if _myUserDALType hasn't got a default ctor.
tobsen
The problem with those patterns is that they kind of assume that the variable is a class level variable. What I am working with is a type that is instantiated in serveral methods locally. (See my question about that.) If I could move it to a single class level variable, then all those Ideas (and others) would work great!
Vaccano
Thanks for the code Marc. It worked great!
Vaccano
I'd raise the question, why is it instantiated in these methods locally? That seems broken/wrong to me, and is almost trivial to correct. If your DAL is essentially worthless after use because it is mutated, take a constructor with IUserDalFactory instead, with one method Create.
JasonTrue
Booja!!! That is a Great Idea! I am going to try that out and see if it works out!I Voted up your answer to this question (and a several others) to "pay" for your great advice. (I would set it as the answer, but it as you stated, Marc's answer was exactly what I had asked for.)
Vaccano
JasonTrue, That worked out Great! Thank you so much for the advice!
Vaccano
A: 

In C# there is a type called "Type". With it you can create a parameter and pass in any valid type.

private void MyMethod(Type myType)
{
  //Do something
}
Loki Stormbringer
+3  A: 

Your real problem is not in the generics or lack thereof. Your real problem is that MyWFCClass is calling both new and the method. As per Misko Hevery, you get the best testability by separating classes that call new from classes that implement logic. Instead of having MyWFCClass somehow know the type that you want to implement and using reflection, just pass the IUserDal object to the constructor, allowing the test harness to pass in a mock object when needed.

If, for some reason, you can't do this and you can't use generics, then you have to do it yourself. Pass a Type object to the MyWFCClass constructor, then use reflection to find and invoke the constructor you want.

JSBangs
+1 for showing "Misko Hevery's code-reviewers-guide"
tobsen
+1  A: 

If IUserDAL defines the interface that your WCF service needs to get its job done, why not just take an instance of it as a constructor parameter? And since WCF requires a default constructor, why not have that default constructor call your parameterized constructor with a default implementation?

public class MyWCFClass : IMyWCFClass
{
    private readonly IUserDAL _userDAL;

    public MyWCFClass()
        : this(new DefaultUserDAL())
    {
    }

    public MyWCFClass(IUserDAL userDAL)
    {
        _userDAL = userDAL;
    }
}

If you're using a dependency injection container, you could expose it as a singleton and satisfy the parameterized constructor by using that singleton:

public MyWCFClass()
    this(Container.Instance.Resolve<IUserDAL>())
{
}

With this approach, your WCF class has everything it needs to get its job done, but it is still unit-testable. Moreover, it is not responsible for creating its dependencies, which is a good thing.

HTH,
Kent

Kent Boogaart
"Moreover, it is not responsible for creating its dependencies, which is a good thing." But now it has a direct dependency on infrastructure and violates the "Container Ignorance" best practice, imho.
tobsen
If WCF provides a hook that you can use to create the service objects, then you could hook into that. Otherwise, I see this as the lesser of two evils.
Kent Boogaart
+1  A: 

Far simpler, and more consistent with other applications that have this problem, would be to extract an interface on UserDal, then you would have something more like:

public MyWCFClass() : this(new UserDAL())
{
}
public MyWCFClass(IUserDal userDAL)
{
    _myUserDAL = myUserDAL;
}

This is also easier to use with dependency-injection frameworks than your proposed method, though that's certainly a secondary concern

(Edited to clarify an alternative solution based on other comments)

If your DAL is essentially worthless after use because it is mutated, take a constructor with IUserDalFactory instead, with one method Create().

JasonTrue
Alas this assumes that _myUserDAL can be a class level object. They way I have it currently structured that is not possible.
Vaccano