PrivateObject have been included in Visual Studio 2005 team edition but since the release of Visual Studio 2008 they have been included in the professional edition, making them available for a wider number of developers. So what’s the fuss all about? Simply as I’ve stated in earlier posts a PrivateObject allows you to access private members of an object. This can be extremely useful when unit testing an application as combined with mock objects these can create the mechanism that allows tests to be conducted in isolation.
For example, take a look at the class diagram below. In this scenario the person class provides the method CalculatePay this will return the amount of pay an employee should receive. To do this the Person class will make a call to the GetHours() method of a persons TimeSheet. The time sheet is declared as a private variable and is therefore inaccessible to anything outside of the Person class.
So how do we test the CalculatePay method? The TimeSheet class will possibly make calls to a database or an enterprise system that holds this data therefore introducing many possible points of failure, so simply testing all at once won’t give us the full benefit of unit testing, it might tell us something has gone wrong but it can’t tell us what or where, and we all love error message that tell us something has gone wrong contact your administrator, personally I hate this type of error, if something has gone wrong I’d like to know what it is exactly as this can save significant time when fixing the problem. The way we get the specific details of what has gone wrong is isolating the tests, only by isolating the tests and completely controlling the situation can we accurately predict what a method should do, and the way I go about this is using Mock objects and the PrivateObject class.
For more details on Mock Objects see my post on the topic.
In this solution I will make the TimeSheet class implement an interface that defines the GetHours method. I will then create a new class called MockTimeSheet that implements the same interface. However the MockTimeSheet class will return a hard coded value for the hours work, this is important as a hard coded value allows me to know exactly what to expect when I call the method. After defining the mock object I will use the PrivateObject to update the private fields of the Person class before running the test.
We’ll start to implement this example and as always we’ll start by implementing the unit tests first.
namespace Payroll{ interface ITimeSheet { double GetHours(); }}
using Payroll;namespace PayrolTests{ public class MockTimeSheet: ITimeSheet { public double GetHours() { return 38; } }}
[TestMethod()]public void CalculatePayTest(){ Person person = new Person(); person.HourlyRate = 10.00; PrivateObject po = new PrivateObject(person); po.SetField("_timeSheet", new MockTimeSheet()); double pay = person.CalculatePay(); Assert.AreEqual(38, pay, "Calculated pay does not match the expected pay!");}
.Net (4) ASP.Net (6) ASP.Net MVC (3) Best Practice (2) Book (4) Burn CD/DVD (1) C# (5) Career (2) Class Library (1) Community event (14) Design (1) Design Patterns (1) Ethernet (1) Home Network (1) i18n (1) Internet Explorer (1) iPod (1) JavaScript (2) jQuery (1) Library (1) Microsoft Translator (1) Ms Office (1) MVC Unit test (1) NWMTUG (6) Open Source (2) PowerShell (13) Python (1) SharePoint (1) SQL Server (1) Team System (1) Test Driven Development (7) Utility (14) Visual C++ (1) Visual Studio 2008 (11) Windows 64 bit (1) Windows 7 (10) Windows XP (3)