ASP.net: Unit Testing with Web Service Proxy Class Dependency

Let's say I have a class like the following:

public class Test{
        private RemoteDoc.Documentation docService = new RemoteDoc.Documentation();
        public Test(){}
}

      

So it makes it difficult to unit test because there is a dependency on the proxy class. You can pass an object through the constructor like this:

public class Test{
        private RemoteDoc.Documentation docService;
        public Test(RemoteDoc.Documentation serv)
        {
               docService = serv;
        }
}

      

Now in my unit tests, I can instantiate the Test class and pass the constructor to the project. However, this solution is not ideal because now other classes need to know about the RemoteDoc.Documentation proxy class and have explicit references to it. What's a good solution to this problem?

EDIT. To be more clear, RemoteDoc.Documentation is a proxy class for a web link. Think of it as if you were using the salesforce.com api and all you really have are the wsdl and disco files.

+2


source to share


5 answers


Your proposed solution, which involves passing the dependency through the constructor, is in fact ideal. This is a well known Dependency Injection (DI) pattern known as Constructor Injection .

At first, it seems that the weakness is actually strong. While it is true that every consumer of the Test class (in your example) must now provide some proxy implementation (I am thereby assuming that the proxy is an interface or abstract base class), they can provide any implementation of that abstraction and not just what you originally meant. Congratulations: you've just opened your class for extensibility !

This still leaves the question of where do you actually place the responsibility for deciding what dependencies go there? You have to do this at the root of the application, in a place called Roots . This is covered in more detail in this SO answer .



You can use the DI container to automatically mount your backups. Some common DI containers:

+3


source


I like RichardOD's approach. One clarification that is useful for unit testing is to use a mock object instead of accessing a real web service. This will mean that your tests will be separate from any external services and will run faster.

You can do this if the code changes like this:

public class Test
{        
     private RemoteDoc.IDocumentation docService;     

     // Constructor providing default for docService
     public Test()
     {
         docService = new RemoteDoc.Documentation();
     }   

     // Constructor for injection
     public Test(RemoteDoc.IDocumentation serv)       
     { 
          docService = serv;        
     }
}

      

Then you create the layout of the documentation object using a fake framework, for example:



... and pass it to the Test constructor (RemoteDoc.IDocumentation serv).

Since RemoteDoc.Documentation is a concrete class, you can make it inherit from RemoteDoc.IDocumentation using a partial class:

namespace RemoteDoc
{
    public interface IDocumentation
    {
        // public functions you want to mock go here
        string GetDocumentation();
    }

    public partial class Documentation : IDocumentation {}
}

      

+2


source


Mark's second approach. For completeness, another option looks like this:

public class Test
{        
     private RemoteDoc.Documentation docService;     

     // Constructor providing default for docService
     public Test()
     {
         docService = new RemoteDoc.Documentation();
     }   

     // Constructor for injection
     public Test(RemoteDoc.Documentation serv)       
     { 
          docService = serv;        
     }
}

      

This means you have a default implementation as well as the ability to plug in a different implementation. Useful if you don't want to use a container.

I've used both approaches in the past. When developing non-trivial software, the DI container approach is usually the best way to go.

0


source


Note that this is much easier using WCF as the service contract is already an interface. Your mock class only needs to implement the interface.

0


source


How about this approach? You will need to write more code to support the functionality in the proxy class. But it will give you flexibility for unit testing.

public interface IDocumentation
{
    // Add whatever functionality you need from RemoteDoc.Documentation
}

public class RemoteDocumnetation : IDocumentation
{
    private RemoteDoc.Documentation docService = new RemoteDoc.Documentation();

    // Implements IDocumentation 
}

public class Test{
        private IDocumentation doc;
        public Test(IDocumentation serv)
        {
               doc= serv;
        }
}

      

0


source







All Articles