Using Pex to test VB.NET code

Posted on December 2, 2008

1


In an ideal world one would write unit-tests before writing any new code following the tenants of TDD. In reality it is quite common to have to rely on a legacy library to do some heavy lifting. Pex is a great new tool available from Microsoft Research that can be used to generate unit-tests automatically. It is smart in that it runs the function you wish to test trying to exercise all possible code paths and ultimately generates unit-tests that can be used to test that function.

Using Pex is as easy as right-clicking on a function in Visual Studio and selecting “Run Pex Explorations”. Pex takes a little while running your function and then displays a table with various values that can be used to test your function.

However if your legacy code happens to be in VB.NET, you cannot just right-click on a function to have Pex generate all unit-tests for you. So that’s where I hope this article will help you.

First, let’s define a scenario. Imagine there’s a class called Transaction and a class called PaymentMethod. A transaction contains various payment-methods. A PaymentMethod indicates whether it requires the cash-drawer to be opened or not (e.g. it doesn’t make sense to pop cash-drawer for a credit-card while it does for cash and debit-card). There’s a read-only property PopCashDrawer on Transaction which returns true if any of the payment-methods requires the cash-drawer to be opened.

Public Class PaymentMethod Private mPopCashDrawer As Boolean Public Property PopCashDrawer() As Boolean Get Return Me.mPopCashDrawer End Get Set(ByVal value As Boolean) Me.mPopCashDrawer = value End Set End Property End Class Public Class Transaction Private mPaymentMethods() As PaymentMethod Public Property PaymentMethods() As PaymentMethod() Get Return Me.mPaymentMethods End Get Set(ByVal value As PaymentMethod()) Me.mPaymentMethods = value End Set End Property Public ReadOnly Property PopCashDrawer() As Boolean Get Dim pop = False For Each pm As PaymentMethod In Me.PaymentMethods pop = pop OrElse pm.PopCashDrawer Next Return pop End Get End Property End Class
To have Pex generate unit-tests for you, here’s what you need to do:

  • First to get started writing unit-tests, just right-click on Transaction in Visual Studio and select “Create Unit Tests”. Make sure you select “Create a new Visual C# project” for Output Project in the dialog that pops up.
  • Next, in the generated class TransactionTest add the following parameterized unit-test (PUT). This guides Pex to come up with different values of arguments to this method which will exercise all code-paths in PopCashDrawer property. Transaction.PopCashDrawer depends upon the PaymentMethods so we take the array of PaymentMethods as argument to our PUT and set it on the transaction before calling PopCashDrawer. The PexAssume.IsNotNull line further guides Pex to say that we don’t really care about the case when transaction is null because we’re really interested in testing PopCashDrawer method.
    [PexMethod] public bool PopCashDrawerPUT(Transaction transaction, PaymentMethod[] paymentMethods) { PexAssume.IsNotNull(transaction); transaction.PaymentMethods = paymentMethods; return transaction.PopCashDrawer; }
  • Next, just right-click on PopCashDrawerPUT and select “Run Pex Explorations”. Pex will then display a table with various values of arguments and the results it got in each case.
  • However since the VB assembly is separate from the C# test-project, Pex will display an icon indicating that it didn’t explore some methods because they were uninstrumented.
  • Make sure you include all methods displayed as uninstrumented and run Pex explorations again.
  • This time around Pex would show 7 different test-cases that it identified.
  • A file named TransactionTest.PopCashDrawerPUT.g.cs would be generated containing unit-tests for those 7 cases. Take a look at that class to see how much work it saved you.
  • You can run the generated unit-tests by going to Test->Run->All Tests in Solution from the main-menu in Visual Studio.
  • Pex would discover inputs which cause PopCashDrawer to throw a NullReferenceException. Determining fixes for those cases is left as an exercise to the reader :)

Download and try out Pex, if you haven’t already!

Advertisement
Tagged: , , ,
Posted in: .NET, Tech/Hacks