Tags: , ,

Naming tests is not a simple task. Personally, in test's name I like to specify a case under the test and expected behaviour or result. Sometimes my tests names are quite verbose, hence long.

Pex might truncate an original name of a parameterized unit test if its name is too long. Current version of Pex (0.18) truncates tests names longer then 40 characters. If you do not like such behaviour, you need to implement a custom Pex test naming logic.

According to Peli it is necessary to implementing the IPexTestNamer interface and PexTestNamerAttributeBase class, and tell Pex to use new naming logic by applying the attribute to a test assembly.

Below is my implementation of the test naming logic that keeps the original test name.

using Microsoft.ExtendedReflection.Collections;
using Microsoft.ExtendedReflection.Metadata.Interfaces;
using Microsoft.ExtendedReflection.Utilities;
using Microsoft.Pex.Engine;
using Microsoft.Pex.Engine.ComponentModel;
using Microsoft.Pex.Engine.TestGeneration;
using Microsoft.Pex.Framework.TestGeneration;

namespace My.Testing.Pex.Extensions {
    public class KeepOriginalTestNamesAttribute : PexTestNamerAttributeBase {
        protected override IPexTestNamer CreateTestNamer(IPexExplorationComponent host) {
            return new TestNamer(host);
        }

        class TestNamer : PexExplorationComponentElementBase, IPexTestNamer {
            private readonly SafeSet<string> _names;

            public TestNamer(IPexExplorationComponent host) : base(host) {
                _names = new SafeSet<string>();
            }

            public bool TryCreateTestName(IPexGeneratedTest test, out string testName) {
                var template = ReflectionHelper.EscapeForMetadataName(test.ExplorationName.Method.ShortName);
                testName = MetadataHelper.GetUniqueNumberedName(_names, template);
                _names.Add(testName);

                return true;
            }
        }
    }
}

Then you can apply the KeepOriginalTestNamesAttribute to a test class or the whole test assembly.

using My.Testing.Pex.Extensions;
using Microsoft.Pex.Framework;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace My.Tests {
    [TestClass, PexClass, KeepOriginalTestNames]
    public partial class ActorBaseTransactionScopeTests {

        ...

    }
}

// or in AssemblyInfo.cs

[assembly: KeepOriginalTestNames]

The code above was written after review of Pex's samples and examination of Microsoft.Pex.Engine.dll in Reflector. So, KeepOriginalTestNamesAttribute does almost the same job as the default Pex's test namer, except checking long tests names against PexFrameworkEnvironmentSettings.MaxMetadataNameLength.Value property to truncate.

Also, while playing with implementation of the TryCreateTestName method, I noticed one useful behaviour. If TryCreateTestName returns false and sets output testName to null, it tells Pex to use the default test naming logic.

Note: everything in this post is related to Pex v0.18 and might obsolete for feature versions.

Related links: