Implementing SOLID principle For TDD on Web Service Reference

What is SOLID?

SOLID are five basic principles which help to create good software architecture. SOLID is an acronym where:-

•S stands for SRP (Single responsibility principle
•O stands for OCP (Open closed principle)
•L stands for LSP (Liskov substitution principle)
•I stands for ISP ( Interface segregation principle)
•D stands for DIP ( Dependency inversion principle)

There are many good article present over the Internet explaining SOLID in details. However, my entire focus will be on how I have implemented this principle on Web Service proxy that I’ve to currently worked on.
Since I am following TDD approach, I will start the development from explaining Unit test first:

Unit testing is all about testing current method (High cohesion and Low coupling). If this method is relaying on another method or an object then you should mock that object/ method so that you can test your method independently.

If you not sure about High cohesion and low coupling principle in OOPS, then I recommend you to learn about SOLID Principles.
You should also read about TDD.

This principle applies even when the dependent code has not been written as yet (well that is why we call it as TDD ;-).

In case of my integration project with sharepoint I was dependent on an external resource. I’d to call a sharepoint web service method GetUserProfileByName, with the endpoint at http://<yourwebsite>/_vti_bin/UserProfileService.asmx

When we used Visual Studio, Add Service reference tool, it creates a proxy class to call the web service:

[System.Web.Services.WebServiceBindingAttribute(Name="UserProfileServiceSoap", Namespace="http://microsoft.com/webservices/SharePointPortalServer/UserProfileService")]
 public partial class UserProfileService : System.Web.Services.Protocols.SoapHttpClientProtocol {…

}

When I saw this proxy file, it has got more than 50+ methods that are exposed. As a principle of SOLID, we should expose only those methods that are important to expose. In our case it is just one method i.e. GetUserProfileByName.
Another important factor we should consider into our design is to how can I assure that the implementation of the sharepoint can be easily replaced with any new external end point such as Active Directory.

To solve all these problems, I just need to follow a I and D pont from SOLID principle.

I – Interface segregation principle – many client-specific interfaces are better than one general-purpose interface.

D – Dependency inversion principle – one should “Depend upon Abstractions. Do not depend upon concretions.”

Now I will not go into the detail of SOLID but these are the steps that you should follow:

1. Import Web service proxy into the project. Now keep in mind that the web service proxy is of partial class. Thus we can create an another partial class and implement a contract.
2. Create a Contract that must contain only those members that you need to expose.

public interface IServiceClient
 {

 bool UseDefaultCredentials { get; set; }
 string Url { get; set; }
 }
public interface IUserProfileServiceClient: IServiceClient
 {
 PropertyData[] GetUserProfileByName(string accountName);
 }

3. Now that I have got contract ready, all I have to do is create a partial class with same signature. In case my case it:

public partial class QueryService : IQueryServiceClient {
 }

NOTE: You don’t need to implement any member because it has been already created by the proxy class.

4. Create a contract of your implementation that you want to test:

public interface IExternalUserService
 {
 User GetUserProfile(string accountName);
 }

5. Create a concrete class:

public class DirectoryUserService : IExternalUserService 
{
 private readonly IUserProfileServiceClient _profileService;
public DirectoryUserService(IUserProfileServiceClient profileService) {
_profileService = profileService;
}
public User GetUserProfile(string accountName)
{
var propertyBag = _profileService.GetUserProfileByName(accountName);
}

Now that we have implemented our method that we want to test, the following UnitTest implementation is using Moq Framework for Stub that is going to pass as IUserProfileServiceClient object.

[TestClass]
public class DirectoryUserServiceTest
{
private PropertyData[] _fakePropertyData;
[TestInitialize]
public void Setup()
{
// Arrange
_fakePropertyData = new[]
{ new PropertyData() {
Name = "WorkEmail",
Values = new[] {new ValueData {Value = "amit.x@xxxxx.com.au"}}
},
new PropertyData()
{
Name = "PictureURL",
Values = new[] {new ValueData {Value = "http://x/xtra/photos/photo152173.jpg"}}
},
new PropertyData() {Name = "FirstName", Values = new ValueData[] {new ValueData() {Value = "Amit"}}},
new PropertyData() {Name = "LastName", Values = new ValueData[] {new ValueData() {Value = "Malhotra"}}},
new PropertyData() {Name = "DirectoryID", Values = new ValueData[] {new ValueData() {Value = "152173"}}},
new PropertyData() {Name = "UserProfile_GUID",Values = new ValueData[] {new ValueData() {Value = Guid.NewGuid()}}
},new PropertyData() {Name = "BusinessUnit", Values = new ValueData[] {new ValueData() {Value = "RBS"}}},

new PropertyData(){Name = "Department",Values = new ValueData[] {new ValueData() {Value = "Partner Engagement"}}
}
};
}
[TestMethod]
public void TestGetUserProfileNotNull()
{
// Arrange
var mockService = new Mock<IUserProfileServiceClient>();
mockService.Setup(r => r.GetUserProfileByName(It.Is<string>(x => x.Equals("amit"))))
.Returns(_fakePropertyData);

IExternalUserService directoryService = new DirectoryUserService(mockService.Object, null);

// Act
User user = directoryService.GetUserProfile("amit");

//Assert
Assert.IsNotNull(user);
}

Point of Interest:

Understand SOLID:

S stands for SRP (Single responsibility principle):- A class should take care of only one responsibility.
O stands for OCP (Open closed principle):- Extension should be preferred over modification.
L stands for LSP (Liskov substitution principle):- A parent class object should be able to refer child objects seamlessly during runtime polymorphism.
I stands for ISP (Interface segregation principle):- Client should not be forced to use a interface if it does not need it.
D stands for DIP (Dependency inversion principle) :- High level modules should not depend on low level modules but should depend on abstraction.

Understand Moq:

Now if you are following the discipline of TDD and are building large scale enterprise application that interacts with services, databases, or other data sources, writing data driven unit tests becomes a challenge. Test setup (for each test) becomes more complicated and challenging than the actual unit test. This is where the concept of Mock comes into picture