PexAssert.Throws in PUT in combination with Run Pex

336 views Asked by At

when I create a PUT that calls a method of the class under test and attribute it with PexMethod, "Run Pex" will use this method and create automatic generated tests for it.

This only works as long as the call to the method is directly in the body of the PUT.

Sample:

This PUT is used by "Run Pex":

[PexGenericArguments(typeof(string))]
[PexGenericArguments(typeof(int))]
[PexGenericArguments(typeof(object))]
[PexMethod]
public string Convert01_ConverterForTypeNotRegistered<T>(
    [PexAssumeUnderTest] ToStringConverter target, T objectToConvert)
{
    var result = "";
    result = target.Convert(objectToConvert);
    return result;
}

This PUT is not used by "Run Pex":

[PexGenericArguments(typeof(string))]
[PexGenericArguments(typeof(int))]
[PexGenericArguments(typeof(object))]
[PexMethod]
public string Convert01_ConverterForTypeNotRegistered_ThrowsInvalidOperationException<T>(
    [PexAssumeUnderTest] ToStringConverter target, T objectToConvert)
{
    var result = "";
    PexAssert.Throws<InvalidOperationException>(() => target.Convert(objectToConvert));
    return result;
}

I want to show that a call to the method always throws this exception, independent of the parameters.

How to achieve this?

I already asked that question a week ago in the official Pex forum of Microsoft but didn't receive a single answer, therefore I am doing a double post here.

The problem can be reproduced like the following:

  1. Have a simple solution with one project with one class with one method.
  2. Right click on that method and choose Run Pex.
  3. In the Pex Exploration Results right click on any entry and choose "Save Test...". It will create a new test project with two relevant files: <class-name>Test.cs and <class-name>Test.<MethodName>.g.cs. In the first file, there is the PUT, in the second files are the specific test methods, one for each parameter Pex chooses. The second file is automatically recreated every time you run pex for a method that has a PUT in the first file.
  4. Right click on the test project and choose "Pex" -> "Delete generated unit tests". This will remove the specific tests from the second file.
  5. Go to the file with the PUT and rename the PUT to an arbitrary name.
  6. Go back to the method from point 1 and again right-click and choose Run Pex.
  7. Pex will create a new file in the test project named `Test..g.cs. It uses the same PUT as before, although you renamed it.
  8. Change the PUT again by leaving the name as it is but changing the content to my second example with PexAssert.Throws.
  9. Again, right click on the test project and choose "Pex" -> "Delete generated unit tests".
  10. Again, right click in the method from point 1 and choose "Run Pex"
  11. Open both of the *.g.cs files in the test project and you will see, that there are no tests. This means, Pex didn't use the PUT. That's the problem :)
1

There are 1 answers

2
configurator On

I just tried running both of your examples, in Visual Studio 2010. I changed the second example to use a class called ThrowingConverter, and these are my silly implementations:

public class ToStringConverter {
    internal string Convert(object objectToConvert) {
        return objectToConvert.ToString();
    }
}

public class ThrowingConverter {
    internal string Convert(object objectToConvert) {
        if (objectToConvert is string) {
            return (string)objectToConvert;
        }
        throw new InvalidOperationException();
    }
}

I ran Pex, and it came up with the following test cases:

  • ToStringConverter:
    • int
      • 0
      • 1
    • string
      • null (fails with NullReferenceException)
      • ""
    • object
      • null (fails with NullReferenceException)
      • new object()
  • ThrowingConverter:
    • int
      • 0
    • string
      • null
      • "" (fails because it returns "")
    • object
      • null
      • "" (fails because it returns "")

This is exactly what I expected it to find, so I don't see your problem really.