
Introduction
When working in a team environment, factors such as limited license keys, security, or network access may hinder the creation of a test environment. In a recent project, one of my requirements was to interface with an existing .NET component. The existing component could not be duplicated in my off-site office environment, and existing security policies would not allow network access. Coding and testing the interface was looking very difficult.
In this article, I will present a method I have used to overcome this problem. In a nutshell, the approach I have used captured the output from an interface query (function call), then serialized the result, wrote it to a file, and emailed it to my office. Later, when I needed to emulate the original component offsite, I called a substitute function with the same parameters and interface as the original, and deserialized my stored result.
This method allows me to mimic exactly the interface for specific tests. The actual concept is quite simple, and the results have been very effective in providing a temporary test environment.
First, a quick look at the class I wish to emulate...
For the purpose of explanation, I have created a class with a complex result set. The actual internal processing is not important, in fact, for this example, it should not matter if I cannot view the internal workings.
Public Class clsMyResult
Public myDS As DataSet
Public strDesc As String
Public myCounter As Int16 = 0
End Class
Public Class clsOriginalClassIWishToEmulate
Public Function MakeResult(ByVal newTables As Int16) As clsMyResult
Dim myResult As New clsMyResult
Dim localDS As New DataSet
For y As Int16 = 1 To newTables
Dim thisTable As New DataTable("table" & y)
thisTable.Columns.Add("tab:" & y & "-col")
Dim myDataRow As DataRow
For x As Int16 = 1 To 10
myDataRow = thisTable.NewRow
myDataRow(0) = "table:" & y & " row:" & x
thisTable.Rows.Add(myDataRow)
Next
localDS.Tables.Add(thisTable)
myResult.myCounter += 1
Next
myResult.myDS = localDS
myResult.strDesc = "There are " & myResult.myCounter & _
" tables in the dataset"
Return myResult
End Function
End Class
Calling clsOriginalClassIWishToEmulate.MakeResult
will produce an output class containing a populated DataSet
, a text string, and counter for the number of tables in the DataSet
.
Capture the output from the original class
The first step in this emulation is to get access to the original class - say on a local developer computer, and run a query against it.
In my case, I will create an instance of the original class and call the function I wish to emulate. I will pass the function the int16
value 10: myOriginalClass.MakeResult(10)
.
Private Sub Serialize_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim myOrginalClass As New clsOriginalClassIWishToEmulate
Dim myResult As clsMyResult
myResult = myOrginalClass.MakeResult(10)
Dim myStreamWriter As StreamWriter
myStreamWriter = New StreamWriter("myresult.xml")
Dim mySerializer As New XmlSerializer(GetType(clsMyResult))
mySerializer.Serialize(myStreamWriter, myResult)
myStreamWriter.Close()
End Sub
After the function returns a value, I serialize the result into an XML file. Note that I need to know the structure of the response for this segment of code to work.
Emulate the original class interface
The next step requires creating a substitute class with the same parameters as the original. This class opens the stored XML file, and returns an actual value (in this case, for '10').
Public Class clsEmulatedClass
Public Function MakeResult(ByVal newTables As Int16) As clsMyResult
Dim myResult As New clsMyResult
Dim myStreamReader As StreamReader
Dim mySerializer As New XmlSerializer(GetType(clsMyResult))
myStreamReader = New StreamReader("myresult.xml")
myResult = mySerializer.Deserialize(myStreamReader)
myStreamReader.Close()
Return myResult
End Function
End Class
Using the new function
The newly created function will operate identical to the original for the function we have emulated. Of course, the returned class is only correct for a particular set of input values.
Enhancements
Further additions to this example could include:
- Store the results for multiple inputs (the emulated class could return the result from the example with the matching input value);
- Emulate properties and;
- Duplicate relevant aspects of the namespace of the original class.
Conclusions
The method displayed here allows the creation of an emulated class. This is particularly useful when the original class is not available due to security, network, or licensing restrictions. Although the method is extremely simple, it can allow a development and testing environment not otherwise possible.
Good luck and happy coding!!