{"id":1165,"date":"2017-06-19T20:21:14","date_gmt":"2017-06-19T20:21:14","guid":{"rendered":"http:\/\/tpodolak.com\/blog\/?p=1165"},"modified":"2017-06-19T20:21:14","modified_gmt":"2017-06-19T20:21:14","slug":"xunit-memberdataattribute-generic-type-inheritance","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2017\/06\/19\/xunit-memberdataattribute-generic-type-inheritance\/","title":{"rendered":"XUnit &#8211; MemberDataAttribute and generic type inheritance"},"content":{"rendered":"<h3>1. Introduction.<\/h3>\n<p>When I was writing <a href=\"https:\/\/github.com\/tpodolak\/Cake.Intellisense\">Cake.Intellisense<\/a> I was playing a lot with <i>Roslyn<\/i> syntax rewriters. The one thing which was pretty important for me at this time was a reliable set of tests which can quickly show if rewritten code is valid <i>C#<\/i> code and if it matches my expectations. As I don\u2019t like to repeat my code I wanted to have a base test class which can be provided with different test cases from inherited classes. The initial implementation looked as follows<\/p>\n<pre lang=\"csharp\">\r\npublic abstract class CSharpSyntaxRewriterTest<T> where T : CSharpSyntaxRewriter\r\n{\r\n    public static IEnumerable<object[]> TestCases { get; set; }\r\n    protected T Subject { get; }\r\n\r\n    private readonly NSubstituteAutoMocker<T> _autoMock;\r\n    \r\n    protected CSharpSyntaxRewriterTest()\r\n    {\r\n        _autoMock = new NSubstituteAutoMocker<T>();\r\n        Subject = _autoMock.ClassUnderTest;\r\n    }\r\n\r\n    [Theory]\r\n    [MemberData(nameof(TestCases))]\r\n    public void Verify(SyntaxRewriterTestCase testCase)\r\n    {\r\n        var inputTree = SyntaxFactory.ParseSyntaxTree(testCase.Input);\r\n        var result = Subject.Visit(inputTree.GetRoot());\r\n\r\n        inputTree.GetDiagnostics().Should().BeEmpty();\r\n        result.GetDiagnostics().Should().BeEmpty();\r\n        result.ToFullString().Should().Be(testCase.ExpectedResult);\r\n    }\r\n}\r\n<\/pre>\n<p>As you can see I have a generic base test class which holds test cases in a static field <i>TestCases<\/i>. The field is static as it is required by <i>XUnit<\/i>, this solution is perfectly valid because a\u00a0static\u00a0field is shared across <a href=\"https:\/\/stackoverflow.com\/a\/3037259\">all instances\u00a0of the same type<\/a>. Having a base test class ready I wanted to write a set of unit tests for following syntax rewriter<\/p>\n<pre lang=\"csharp\">\r\npublic class InternalToPublicClassModifierSyntaxRewriter : CSharpSyntaxRewriter\r\n{ \r\n    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)\r\n    {\r\n        var internalModifierIndex = node.Modifiers.IndexOf(SyntaxKind.InternalKeyword);\r\n            \r\n        if (internalModifierIndex > -1)\r\n        {\r\n            var tokenInList = node.Modifiers[internalModifierIndex];\r\n            var updatedModifiers = node.Modifiers.Replace(tokenInList,\r\n                   SyntaxFactory.Token(SyntaxKind.PublicKeyword).WithLeadingTrivia(tokenInList.LeadingTrivia)\r\n                        .WithTrailingTrivia(tokenInList.TrailingTrivia));\r\n\r\n            node = node.WithModifiers(updatedModifiers);\r\n         }\r\n\r\n         return base.VisitClassDeclaration(node);\r\n    }\r\n}\r\n<\/pre>\n<p>The rewriter shown above is a very simple piece of code which replaces internal class modifier with a public one. Writing the tests for that class was supposed to be very easy, I just had to provide test cases with input code and expected result.<\/p>\n<pre lang=\"csharp\">\r\npublic class InternalToPublicClassModifierSyntaxRewriterTests\r\n        : CSharpSyntaxRewriterTest<InternalToPublicClassModifierSyntaxRewriter>\r\n{\r\n    static InternalToPublicClassModifierSyntaxRewriterTests()\r\n    {\r\n        TestCases = new[]\r\n        {\r\n            new[] { ReplacesInternalModifierWithPublic() },\r\n            new[] { LeavesModifiersIntactWhenClassModifierPublic() },\r\n            new[] { LeavesModifiersIntactWhenClassModifierProtected() }\r\n        };\r\n    }\r\n\r\n    private static SyntaxRewriterTestCase ReplacesInternalModifierWithPublic()\r\n    {\r\n        return new SyntaxRewriterTestCase(nameof(ReplacesInternalModifierWithPublic), \r\n                \"internal class Foo { }\", \"public class Foo { }\");\r\n    }\r\n\r\n    private static SyntaxRewriterTestCase LeavesModifiersIntactWhenClassModifierPublic()\r\n    {\r\n        return new SyntaxRewriterTestCase(nameof(LeavesModifiersIntactWhenClassModifierPublic),\r\n                \"public class Foo { }\", \"public class Foo { }\");\r\n    }\r\n\r\n    private static SyntaxRewriterTestCase LeavesModifiersIntactWhenClassModifierProtected()\r\n    {\r\n        return new SyntaxRewriterTestCase(nameof(LeavesModifiersIntactWhenClassModifierProtected),\r\n                \"protected class Foo { }\", \"protected class Foo { }\");\r\n    }\r\n}\r\n<\/pre>\n<p>Unfortunately running the tests resulted in <i>InvalidOperationException<\/i> being thrown from <i>XUnit<\/i><br \/>\n<a href=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest.png\"><img decoding=\"async\" src=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest.png\" alt=\"\" height=\"374\" class=\"aligncenter size-full wp-image-1168\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest.png 1103w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest-150x51.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest-300x102.png 300w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/FailedTest-1024x347.png 1024w\" sizes=\"(max-width: 1103px) 100vw, 1103px\" \/><\/a><br \/>\nIf you look closely at the message you will notice that the <i>TestCases<\/i> field used for providing data was not initialized, which means that the static constructor of class <i>InternalToPublicClassModifierSyntaxRewriterTests<\/i> was not run. That was pretty surprising for me that is why I wanted to investigated the issue a bit more. <\/p>\n<h3>2. Investigation. <\/h3>\n<p>I started from going back to the basics. As we probably all know, the static constructor is triggered when one of the following events occur:<\/p>\n<ul>\n<li>An instance of the class type is created.<\/li>\n<li>Any of the static members of the class type are referenced<\/li>\n<\/ul>\n<p>The first condition is not met because instance of the test class is created after test cases are enumerated. That is why member data fields have to be a static fields\/properties etc. When it comes to second condition the situation in here is a bit more complicated but if you take a look at the <a href=\"https:\/\/github.com\/xunit\/xunit\/blob\/bccfcccf26b2c63c90573fe1a17e6572882ef39c\/src\/xunit.core\/MemberDataAttributeBase.cs\">MemberDataAttributeBase<\/a> class<\/p>\n<pre lang=\"csharp\">\r\npublic override IEnumerable<object[]> GetData(MethodInfo testMethod)\r\n{\r\n    Guard.ArgumentNotNull(\"testMethod\", testMethod);\r\n\r\n    var type = MemberType ?? testMethod.DeclaringType;\r\n    var accessor = GetPropertyAccessor(type) ?? GetFieldAccessor(type) ?? GetMethodAccessor(type);\r\n    \/\/ implementation omitted for brevity  \r\n}\r\n<\/pre>\n<p>you will notice that member data looks for properties in <i>DeclaringType<\/i> of method. In my case declaring type is <\/p>\n<pre lang=\"csharp\">\r\nXUnitMemberDataAndInheritance.CSharpSyntaxRewriterTest`1[[XUnitMemberDataAndInheritance.InternalToPublicClassModifierSyntaxRewriter]]\r\n<\/pre>\n<p>not<\/p>\n<pre lang=\"csharp\">\r\nInternalToPublicClassModifierSyntaxRewriterTests\r\n<\/pre>\n<p>So when <i>XUnit<\/i> accesses <i>TestCase<\/i> property the static constructor from <i>InternalToPublicClassModifierSyntaxRewriterTests<\/i> class will not be called either as the types does not match.<\/p>\n<h3>3. Solution.<\/h3>\n<p>In order to bend the behavior of <i>XUnit<\/i> to my needs, I had to ensure that the static constructor from inherited class is called. Fortunately, workaround is pretty straightforward &#8211; I had to introduce a custom <i>MemberDataAttribute<\/i> which calls static constructor from <i>ReflectedType<\/i> manually<\/p>\n<pre lang=\"csharp\">\r\n[DataDiscoverer(\"Xunit.Sdk.MemberDataDiscoverer\", \"xunit.core\")]\r\n[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]\r\npublic class CustomMemberDataAttribute : MemberDataAttributeBase\r\n{\r\n    public CustomMemberDataAttribute(string memberName, params object[] parameters)\r\n            : base(memberName, parameters)\r\n    {\r\n    }\r\n\r\n    public override IEnumerable<object[]> GetData(MethodInfo testMethod)\r\n    {\r\n        var type = MemberType ?? testMethod.ReflectedType;\r\n        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);\r\n        return base.GetData(testMethod);\r\n    }\r\n\r\n    protected override object[] ConvertDataItem(MethodInfo testMethod, object item)\r\n    {\r\n        if (item == null)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        var array = item as object[];\r\n        if (array == null)\r\n        {\r\n            throw new ArgumentException(\r\n                    $\"Property {MemberName} on {MemberType ?? testMethod.ReflectedType} yielded an item that is not an object[]\");\r\n        }\r\n            return array;\r\n    }\r\n}\r\n<\/pre>\n<p>Now all I have to do is use newly created attribute in <i>CSharpSyntaxRewriterTest<T><\/i> test class<\/p>\n<pre lang=\"csharp\">\r\n[Theory]\r\n[CustomMemberData(nameof(TestCases))]\r\npublic void Verify(SyntaxRewriterTestCase testCase)\r\n{\r\n    \/\/ implementation omitted for brevity        \r\n}\r\n<\/pre>\n<p>From now on all of the test cases will be run correctly<br \/>\n<a href=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest.png\"><img decoding=\"async\" src=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest.png\" alt=\"\" height=\"358\" class=\"aligncenter size-full wp-image-1169\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest.png 1107w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest-150x49.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest-300x97.png 300w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2017\/06\/xunit-memberdataattribute-and-generic-type-inheritance\/GreenTest-1024x331.png 1024w\" sizes=\"(max-width: 1107px) 100vw, 1107px\" \/><\/a><br \/>\nSource code for this post can be found <a href=\"https:\/\/github.com\/tpodolak\/Blog\/tree\/master\/XUnitMemberDataAndInheritance\">here<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Introduction. When I was writing Cake.Intellisense I was playing a lot with Roslyn syntax rewriters. The one thing which was pretty important for me at this time was a reliable set of tests which can quickly show if rewritten code is valid C# code and if it matches my expectations. As I don\u2019t like [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[319],"tags":[320],"class_list":["post-1165","post","type-post","status-publish","format-standard","hentry","category-xunit","tag-xunit"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=1165"}],"version-history":[{"count":15,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1165\/revisions"}],"predecessor-version":[{"id":1182,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1165\/revisions\/1182"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=1165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=1165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=1165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}