by Paulo Morgado via Paulo Morgado : C# on 1/19/2010 12:26:00 AM
Visual Studio uses Publicize to create accessors public for private members and types of a type.
But when you try to set elements of a private array of elements of a private type, things get complicated.
Imagine this hypothetic class to test:
public static class MyClass { private static readonly MyInnerClass[] myArray = new MyInnerClass[10]; public static bool IsEmpty() { foreach (var item in myArray) { if ((item != null) && (!string.IsNullOrEmpty(item.Field))) { return false; } } return true; } private class MyInnerClass { public string Field; } }
If I want to write a test for the case when the array has “non empty” entries, I need to setup the array first.
Using the accessors generated by Visual Studio, I would write something like this:
[TestClass()] public class MyClassTest { [TestMethod()] public void IsEmpty_NotEmpty_ReturnsFalse() { for (int i = 0; i < 10; i++) { MyClass_Accessor.myArray[i] = new MyClass_Accessor.MyInnerClass { Field = i.ToString() }; } bool expected = false; bool actual; actual = MyClass.IsEmpty(); Assert.AreEqual(expected, actual); } }
But the test will fail because, although the elements of the private array myArray can be read as MyClass_Accessor.MyInnerClass instances, they can’t be written as such.
To do so, the test would have to be written like this:
[TestClass()] public class MyClassTest { [TestMethod()] public void IsEmpty_NotEmpty_ReturnsFalse() { for (int i = 0; i < 10; i++) { MyClass_Accessor.ShadowedType.SetStaticArrayElement("myArray", new MyClass_Accessor.MyInnerClass { Field = i.ToString() }.Target, i); } bool expected = false; bool actual; actual = MyClass.IsEmpty(); Assert.AreEqual(expected, actual); } }
But, this way, we loose all the strong typing of the accessors because we need to write the name of the array field.
Because the accessor for the field is a property, we could write a set of extension methods that take care of getting the field name for us. Something like this:
public static class PrivateypeExtensions { public static void SetStaticArrayElement<T>(this PrivateType self, Expression<Func<T[]>> expression, T value, params int[] indices) { object elementValue = (value is BaseShadow) ? (value as BaseShadow).Target : value; self.SetStaticArrayElement( ((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name, elementValue, indices); } public static void SetStaticArrayElement<T>(this PrivateType self, Expression<Func<T[]>> expression, BindingFlags invokeAttr, T value, params int[] indices) { object elementValue = (value is BaseShadow) ? (value as BaseShadow).Target : value; self.SetStaticArrayElement( ((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name, invokeAttr, elementValue, indices); } }
Now, we can write the test like this:
[TestClass()] public class MyClassTest { [TestMethod()] public void IsEmpty_NotEmpty_ReturnsFalse() { for (int i = 0; i < 10; i++) { MyClass_Accessor.ShadowedType.SetStaticArrayElement(() => MyClass_Accessor.myArray, new MyClass_Accessor.MyInnerClass { Field = i.ToString() }, i); } bool expected = false; bool actual; actual = MyClass.IsEmpty(); Assert.AreEqual(expected, actual); } }
It’s not the same as the first form, but it’s strongly typed and we’ll get a compiler error instead of a test run error if we change the name of the myArray field.
You can find this and other tools on the PauloMorgado.TestTools on CodePlex.
Original Post: How To Set Elements Of An Array Of A Private Type Using Visual Studio Shadows
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.