How far do you want to go with Generics on test automation?

I’ve been working with certain developers and testers around providing Generics to test certain Web API’s or WebSerices. With that in mind, questions come up such as what if I want to test objects (models) dynamically so I can write a test method that takes a model name then validate certain properties. Yes, you can do this through reflection but how far do you want to go with this? In the testing world, we want to make sure we have good documentation particularly on failure scenarios. We also have to think about that our code are also the source of test case documentation. It’s a fine line where you want to extend generics with reflection vs calling API’s appropriately. Take the following example:

Example 1:

 //Using Reflection to invoke methods
var objModel = GetTheType(namespaceName + "." + objModelName);
var helpergenericclass = GetTheType("XXX.XXX.XXX.HelperClassWebApi");
Task<AuthTokenResponse> userAuthToken = HelperClassWebApi.GetUserToken(userId, userPsw);
MethodInfo mi = helpergenericclass.GetMethod("GetObject");
MethodInfo miConstructed = mi.MakeGenericMethod(objModel);
var arguments = new object[] { webSrvcUrl, resource, method, urlParams, true, userAuthToken.Result };
var response = miConstructed.Invoke(null, arguments);
		      var profile = (UserProfile) response;
Assert.IsNotNull(profile, "Test Case Failed: User Profile is Null");
Assert.IsNotNull(profile.Advisories, "Test Case Failed: Advisories Object is Null");
Assert.IsFalse(String.IsNullOrEmpty(profile.LastName), "Test Case Failed: Last Name is Empty");

Example 2:

//Calling methods not using Reflection
var profileGet = HelperClassWebApi.GetObject<UserProfile>(webSrvcUrl, resource, method, urlParams, true, userAuthToken.Result);
Assert.IsNotNull(profileGet, "Test Case Failed: User Profile is Null");
Assert.IsNotNull(profileGet.Advisories, "Test Case Failed: Advisories Object is Null");
Assert.IsFalse(String.IsNullOrEmpty(profileGet.LastName), "Test Case Failed: Last Name is Empty");  

In both Examples, both achieve the same results. However as a developer or tester, strongly typed (type safe) name comes in handy at least when writing test automation. For Example 1 and in reflection you have to ensure that you:

  • Ensure that the arguments you pass will exactly match the parameters specified in the called method
  • You need to verify if the called method returns data back or not (void or T)

This practice while good in generics, provides more overhead to write automated tests for users who share the same codebase. More importantly if you engage with other developers to write automated tests, they end up spending more time understand the code. Even worse, if an issue does occur, you need to ensure that the cause is not through the test code rather a valid failing test.

In this case, Example 2 was sufficient so you return a strongly type name and during compile time (in development), intelliSense on invoking the method and finally knowing that the method returns an object back or not.

In summary, make sure you use generics the right way and the right way is to look at adoption and ease of use. There are many practices out in the real world and in my experience develop generics. There are instances. Good article to read up on:

An Introduction to C# Generics


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: