Looking into Visual Studio 2017 features I found that Pex was back in the form of IntelliTest. It was actually introduced in VS2015 but I’ve never seen it. Time to give it a spin.
For this I use my Traffic Demo. The solution shows how a state pattern can be used to implement complex business rules. There are already unit tests because it is a test driven development demo. I will add extra unit tests with the IntelliTest feature.
Open the solution in Visual Studio and go to the method to IntelliTest. Then open the context menu and IntelliTest > Create IntelliTest. A dialog will ask for some naming convention.
After completion there is a generated partial class that contains code to test the method selected. Some lines of comment suggest to add an Assert. I add the Assert that confirms a property is set during the action on the state.
[PexMethod] public void VooruitIntelliTest([PexAssumeUnderTest]Auto target) { target.Vooruit(); // English: drive // TODO: add assertions to method AutoIntelliTest.VooruitIntelliTest(Auto) Assert.IsInstanceOfType(target.Verplaatsing, typeof(NaarVoren)); }
Now run the IntelliTests by going into the context menu and IntelliTest > Run IntelliTest. The result is shown in the IntelliTest Exploration Results. Open the warnings and see the Object creation warning. This is because there is no way for IntelliTest to vary between different states. Context menu on the warning and click Fix.
This will create a simple factory class that can be altered to allow variation between different states. Do this by adding parameters to the static Create method.
[PexFactoryMethod(typeof(Auto))] public static Auto Create(Verplaatsing verplaatsing, string bestuurder) { Auto auto = new Auto // English: car { Verplaatsing = verplaatsing, // English: direction Bestuurder = bestuurder // English: driver }; return auto; }
Now run the IntelliTests again. This time some exceptions are reported.
The first is the NullReferenceException, caused by passing null for the first parameter to the Create method above. We need to tell IntelliTest to not pass null. For this the PexAssumeNotNull attribute is available which I add to the first parameter.
[PexFactoryMethod(typeof(Auto))] public static Auto Create( [PexAssumeNotNull]Verplaatsing verplaatsing, string bestuurder) { // rest of factory method }
The other exception is a exception thrown by my code because a businessrule is violated. In English the businessrule is: in case the car is driving backwards and you put it in drive an accident (ongeluk) is thrown. Again with an attribute this can be told to IntelliTest: PexAllowedExceptionFromType.
[PexMethod] [PexAllowedExceptionFromType(typeof(Ongeluk), typeof(NaarAchteren))] public void VooruitIntelliTest([PexAssumeUnderTest]Auto target) { // rest of intellitest }
This adds the ExpectedException attribute on the generated unit test in case the exception of type Ongeluk is thrown from the type NaarAchteren (English: Reverse) You can see this in the generated g.cs file.
// part of AutoIntelliTest.VooruitIntelliTest.g.cs [TestMethod] [PexGeneratedBy(typeof(AutoIntelliTest))] [ExpectedException(typeof(Ongeluk))] public void VooruitIntelliTestThrowsOngeluk41() { Auto auto; NaarAchteren s0 = new NaarAchteren(); auto = AutoFactory.Create((Verplaatsing)s0, (string)null); this.VooruitIntelliTest(auto); }
Now compile the intellitest project and run the tests from Test Explorer with code coverage enabled. Code coverage is 100%. Good job!
Code available on github.
Final thoughts
I prefer test driven development and create the unit test first. This method of generating unit tests feels like cheating. On the other hand it creates some extra tests to up the code coverage and discovery of edge cases. Use it wise grasshopper.