Jun 06 2008
VSTS Testing Private Members and Methods using Accessors
as explained in my previous post, we can easily test the public methods of a class. At the end of that blog, I mentioned about private accessors. this post explains that cool feature.
assume we have a class as follows:
public class BusinessObject { private const int MagicFactor = 18; private int CalculateConfidentialValue(int baseAmount) { return baseAmount * BusinessObject.MagicFactor; } }
obviously, the method and magic factor are not super-confidential or anything. but let us pretend, they are.
here both the constant and the method are private. needless to say, the following Test Method won’t compile.
[TestMethod()] public void WontCompileCalculateConfidentialValueTestMethod() { BusinessObject myObject = new BusinessObject(); int magicFactor = BusinessObject.MagicFactor; Assert.AreEqual(18, magicFactor); Assert.AreEqual(magicFactor * 2, myObject.CalculateConfidentialValue(2)); }
this is where private accessors help us. Private Accessors help us to access the Private members and Methods of an object, so that we can unit test them.
- go to the BusinessObjects class file
- Right Click >> Create Private Accessor >> Test project..
something similar is created behind the scenes:
[Shadowing("PrivateAccessorDemo.BusinessObject")] public class BusinessObject_Accessor : BaseShadow { protected static PrivateType m_privateType; [Shadowing(".ctor@0")] public BusinessObject_Accessor(); public BusinessObject_Accessor(PrivateObject __p1); [Shadowing("MagicFactor")] public static int MagicFactor { get; } public static PrivateType ShadowedType { get; } public static BusinessObject_Accessor AttachShadow(object __p1); [Shadowing("CalculateConfidentialValue@1")] public int CalculateConfidentialValue(int baseAmount); }
you don’t need to try and understand that. all you need is how to use the created code, and here it is:
[TestMethod()] public void CalculateConfidentialValueTestMethod() { BusinessObject_Accessor target = new BusinessObject_Accessor(); int magicFactor = BusinessObject_Accessor.MagicFactor; Assert.AreEqual(18, magicFactor); Assert.AreEqual(magicFactor * 2, target.CalculateConfidentialValue(2)); }
As we can see, we could now test the Private Member and the Private Method using the accessor.
Another good thing about the private accessors now, is the way we can test for exceptions thrown by the method.
Assume we modify our source method to:
public class BusinessObject { private const int MagicFactor = 18; private int CalculateConfidentialValue(int baseAmount) { if (baseAmount == 0) { throw new ArgumentException("argument cannot be zero.", "baseAmount"); } return baseAmount * BusinessObject.MagicFactor; } }
To test, if an argument exception is indeed thrown, we could write an unit test case as follows:
[TestMethod()] [ExpectedException(typeof(System.ArgumentException))] public void CalculateConfidentialValueWithZeroParameterTestMethod() { BusinessObject_Accessor target = new BusinessObject_Accessor(); target.CalculateConfidentialValue(0); }
- I believe this is possible, because of the Shadowing attribute which is now used for private accessors changing the way exceptions are returned by the target object.
- Before the Shadow based reflection, the accessor always threw a System.Reflection.TargetInvocationException and the inner exception needed to be evaluated.
- The concise attribute based exception check for ArgumentException could not be checked.
Private Accessors are very useful, when you are testing the Business Layer or OM.
there’s a solution to every problem; given enough time and money..
Buy:Advair.Lipothin.Lasix.Benicar.Ventolin.Zocor.SleepWell.Female Pink Viagra.Wellbutrin SR.Amoxicillin.Nymphomax.Zetia.Acomplia.Cozaar.Buspar.Lipitor.Seroquel.Prozac.Female Cialis.Aricept….
Buy:Lipitor.Female Cialis.Seroquel.Zocor.Lipothin.Prozac.Cozaar.Advair.Lasix.Benicar.Female Pink Viagra.Aricept.SleepWell.Amoxicillin.Ventolin.Wellbutrin SR.Acomplia.Zetia.Buspar.Nymphomax….