posted on Tuesday, September 14, 2004 8:46 PM by anoras

The inner works of private method testing in VS Team System

While researching for a presentation of code quality tools in Visual Studio .NET 2005 Team System I discovered that you can create unit tests for private methods in your test fixtures. Since the target and the test fixture are two separate classes they do not have access to each others private members, still the Team System unit testing framework enables you to access these. As a curious cat, I had to investigate how this is accomplished.
The following snippet is taken form the Woodgrove Bank walkthrough project's BankAccount class:
1// private method:
2private accountType GetAccountType
3{
4 get
5 {
6 if (Balance > 15.00)
7 return accountType.Platinum;
8 else
9 return accountType.Gold;
10 }
11}
And this is the unit-test code generated by the Team System unit test generator:
1/// <summary>
2/// GetAccountTypeTest is a test case for GetAccountType
3/// </summary>
4 [TestMethod()]
5 public void GetAccountTypeTest()
6 {
7 // TODO: Initialize to an appropriate value
8 string customerName = null;
9 // TODO: Initialize to an appropriate value
10 double balance = 0;
11
12 BankAccountNS.BankAccount target = new BankAccountNS.BankAccount(customerName, balance);
13
14 // TODO: Assign to an appropriate value for the property
15 BankAccountNS.BankAccount.accountType val = BankAccountNS.BankAccount.accountType.Gold;
16
17 BankAccount.BankAccountAccessor accessor = new BankAccount.BankAccountAccessor(target);
18 Assert.AreEqual(val, accessor.GetAccountType);
19
20 Assert.Inconclusive("Verify the correctness of this test method.");
21 }
Take note of the highlighted line. Instead of creating an instance of the BankAccount class directly the test case uses a BankAccountAccessor class. This class is also used to access fields and methods. However this class is not a part of the project or is it?
While no class is shown in the solution explorer, you will find a source file called CodeGenAccessors.cs in the project directory. This is an auto generated file and it contains the various accessor classes for your target.
The following snippet shows the proxy for the private GetAccountType method.

1    public BankAccountNS.BankAccount.accountType GetAccountType {
2 get {
3 return ((BankAccountNS.BankAccount.accountType)(m_privateObject.GetProperty("GetAccountType")));
4 }
5 }
6

Still the generated accessor is still a separate class from the test target, so how does this work?
The answer is simple. The testing framework applies a little reflection magic beneath the covers. The m_privateObject field is an instance of Microsoft.VisualStudio.QualityTools.UnitTesting.Framework.PrivateObject which uses the Type’s InvokeMember method to invoke the get property in the above example.
To use this technique in your own code simply do this:
1public class Thief {
2 public static void Main()
3 {
4 Safe somebodyElsesSafe=new Safe();
5 Console.WriteLine((string)somebodyElsesSafe.GetType().InvokeMember("secret",BindingFlags.GetField|BindingFlags.Instance|
6BindingFlags.NonPublic,null,somebodyElsesSafe,null));
7 }
8}
9public class Safe {
10 private string secret="This is a secret lock inside a safe!";
11}

This is a cunning solution to a classic unit testing problem. And although extra code is included in your project while testing it is much more elegant than making private members public, which was the previous technique of choice, while testing.

Comments

# free download ringtones for cingular phone @ Sunday, October 28, 2007 4:05 PM

free download ringtones for cingular phone

Anonymous

# free download ringtones for cingular phone @ Sunday, October 28, 2007 4:05 PM

free download ringtones for cingular phone

Anonymous

# free download ringtones for cingular phone @ Sunday, October 28, 2007 4:05 PM

free download ringtones for cingular phone

Anonymous