xunit / devices.xunit

xUnit.net Runners for Devices
Other
73 stars 36 forks source link

Theories Using Object Parameters Are Displayed As Single Test Cases in GUI and Do Not Provide Case in Results File #46

Closed Jyosua closed 8 years ago

Jyosua commented 8 years ago

We have some test cases that do something like the following:

    public class ExampleTestClass
    {
        public static IEnumerable<object[]> MemberDataObject
        {
            get
            {
                return new[] {
                    new object[] { new TestObjectAlpha() },
                    new object[] { new TestObjectBeta() }
                };
            }
        }

        [Theory, MemberData("MemberDataObject")]
        public void ExampleTestMethodUsingObjectParameters(TestObject pTestObject)
        {
                //Test code here
        }

Where TestObjectAlpha and TestObjectBeta inherit from TestObject.

What ends up happening, is that the test runner GUI only has ONE case listed to run -- ExampleTestMethodUsingObjectParameters(). Additionally, the test result output from the writer provides no parameters and simply lists this test twice, since there were two cases. That means that if one of the tests failed, I'm not provided any information as to which one failed.

If you use literals or strings, the GUI shows each case individually, and the parameters are provided both in the GUI and from the results writer:

    public class ExampleTestClass
    {
        public static IEnumerable<object[]> MemberDataObject
        {
            get
            {
                return new[] {
                    new object[] { "TestCaseAlpha" },
                    new object[] { "TestCaseBeta" }
                };
            }
        }

        [Theory, MemberData("MemberDataObject")]
        public void ExampleTestMethodUsingStringParameters(string pTestCase)
        {
                //Test code here
        }

This results in individual cases in the GUI:

Assembly.Name.ExampleTestClass.ExampleTestMethodUsingStringParameters(pTestCase: "TestCaseAlpha") Assembly.Name.ExampleTestClass.ExampleTestMethodUsingStringParameters(pTestCase: "TestCaseBeta")

And the results writer also has this information. Since the runner already has to do some kind of reflection, it seems to me that it would make more sense just to output the object name as a string and make it look like so:

Assembly.Name.ExampleTestClass.ExampleTestMethodUsingObjectParameters(pTestObject: TestObjectAlpha()) Assembly.Name.ExampleTestClass.ExampleTestMethodUsingObjectParameters(pTestObject: TestObjectBeta())

Are there some other considerations for why this is not done, like speed? Currently, to get this desired operation, I am forced to do the following instead:

    public class ExampleTestClass
    {
        private static Dictionary<string, TestObject> _testCases = new Dictionary<string, TestObject>
        {
            { "TestObjectAlpha", new TestObjectAlpha() },
            { "TestObjectBeta", new TestObjectBeta() }
        };

        public static IEnumerable<object[]> MemberDataObject
        {
            get
            {
                return new[] {
                    new object[] { "TestObjectAlpha" },
                    new object[] { "TestObjectBeta" }
                };
            }
        }

        [Theory, MemberData("MemberDataObject")]
        public void ExampleTestMethod(string pTestCase)
        {
                //Test code here references _testCases[pTestCase] instead
        }

which produces the following:

Assembly.Name.ExampleTestClass.ExampleTestMethod(pTestCase: "TestObjectAlpha") Assembly.Name.ExampleTestClass.ExampleTestMethod(pTestCase: "TestObjectBeta")

clairernovotny commented 8 years ago

/cc @bradwilson can we just ToString() other types used in this context for the display names?

bradwilson commented 8 years ago

This is not about display names; this is about the fact that the theory data is not serializable.

clairernovotny commented 8 years ago

If the custom types implemented IXunitSerializable, would it work better?

bradwilson commented 8 years ago

Yes.

Jyosua commented 8 years ago

I wrote a wrapper object that implements the IXunitSerializable interface and that corrected this issue for me. Sorry for the bother. I partially modified code I saw Brad posted here: https://github.com/xunit/xunit/issues/429

    public class MemberDataObject : IXunitSerializable
    {
        public MemberDataObject() { }  // Needed for deserializer

        public MemberDataObject(object pTestObject)
        {
            TestObject = pTestObject;
            TestObjectName = TestObject.GetType().Name;
        }

        public object TestObject { get; private set; }
        public string TestObjectName { get; private set; }

        public void Deserialize(IXunitSerializationInfo serializationInfo)
        {
            TestObject = serializationInfo.GetValue<string>("TestObjectName");
        }

        public void Serialize(IXunitSerializationInfo serializationInfo)
        {
            serializationInfo.AddValue("TestObjectName", TestObjectName);
        }

        public override string ToString()
        {
            return TestObjectName + "()";
        }

        public T GetObject<T>()
        {
            if (TestObject is T)
                return (T)TestObject;
            else
                return default (T);
        }
    }

Edit: Copied the wrong implementation; that one had errors. This one works.

clairernovotny commented 8 years ago

Thanks, closing this out then.