Monday 26 May 2014

Visual Studio Upgrade : Private accessor vs Private Object/Type

There are some interesting scenarios that can arise when upgrading a solution built using Visual Studio 2010 to a higher version of Visual Studio (2012 or 2013). If the original solution uses "Private Accessor" feature, a feature that was introduced in an earlier version of Visual Studio to allow users to write test cases that can target private methods, fields or properties of a class, then there is a possibility that you might get compilation error similar to the one described below  after upgrading the solution (along with a warning that this particular feature is deprecated):

System.IO.FileNotFoundException: Could not load file or assembly 'Fully Qualified Assembly Name' or one of its dependencies. The system cannot find the file specified.
File name: 'Fully Qualified Assembly Name'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.UnitySerializationHolder.GetRealObject(StreamingContext context)

   at Microsoft.VisualStudio.TestTools.UnitTesting.Publicize.Shadower.ShadowAssemblyHelper(ShadowerOptions options)
   at Microsoft.VisualStudio.TestTools.UnitTesting.Publicize.Shadower.ShadowAssembly(AppDomain domain, ShadowerOptions options)
   at Microsoft.VisualStudio.TestTools.UnitTesting.Publicize.Shadower.ShadowAssembly(ShadowerOptions options)
   at Microsoft.VisualStudio.TestTools.BuildShadowReferences.BuildShadowTask.Execute()
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.d__20.MoveNext()


As it happened in my case, chances are the all the necessary references required to load the assembly are  already in place (I verified it using FusLogVw) and yet the compilation process causes grief.
 
So I resorted to the Visual Studio Unit Test Upgrade guidance description and decided to replace the private accessors with PrivateObject and PrivateType. There are some fine examples (#1, #2, #3 etc.) available over the internet that explain about usage of these with respect to instance level access and Type level access.
 
Though in my personal opinion using this approach is just marginally better than using "InternalsVisibleTo" approach - In ideal circumstances, we should  not be worried about internal implementation when dealing with unit test cases. They should always cater to public API only and the effort spent in designing the application should need to pay attention to "testability" of the application as well. If we do that, then we will never need to go back to such hacks (if I may say so). Nevertheless, these are quite interesting wrappers that may be useful in things other than unit testing too for example - cases when you do not want to write elaborate code that uses Reflection etc.

Monday 19 May 2014

HTML Input control's title and maxlength attribute - interesting behavior

Modern web development tools like ASP.NET, JQuery etc. are very much advanced compared to the tools and technologies available in the past. Add HTML5 to this and you feel the set piece is complete. However, some times you run into weird issues because everything seems to be a given specially when most of the browsers support many common standards like CSS3, HTML5 attributes etc. Recently I ran into an interesting issue.

We use ASP.NET MVC, JQuery, JQuery.Validate and Unobtrusive JavaScript validation in one of the web application. In an attempt to accomplish a requirement, my team mate ended with a model that had a property like following:

[StringLength(12)]

[RegularExpression(@"^-?\d{1,5}(\.\d{1,5})?$")]

public string SomeNumber { get; set; }

It was needed to show this property on a text box and a piece of information was required to be shown in tool tip when user hovered over it. So cshtml file markup looked like following:

<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12">

<input title="this is a test tool tip." class="form-control"

data-val="true"

data-val-number="Must be a valid number"

data-val-regex="Invalid pattern."

data-val-regex-pattern="^-?\d{1,5}(\.\d{1,5})?$"

id="inputItem" maxlength="12" name="inputItem" type="number" value="">

<span class="field-validation-valid" data-valmsg-for="inputItem" data-valmsg-replace="true"></span>

</div>

Nothing particularly wrong with this. However this leads to interesting behavior across browsers. On Internet Explorer 11 it works alright i.e. if you enter a value that does not match pattern, it shows correct message. Input values like 123456, 123456., 123456.1, 12345678.1345 produce correct error message "Invalid pattern".
 
However on Chrome, FireFox, Opera it showed an interesting behavior. For input values like 12345678.134 it produced correct message like "Invalid pattern". However when input length is more than the value set in maxlength attribute e.g. 12345678.1346 the error message changes to "this is a test tool top." :)

 
After some intriguing investigation through hit/try and some searching over the Internet, it turned out that the issue was with "maxlength" attribute. Once I changed it to use the default HTML helper that generates client side length validation code (which does not use maxlength attribute), the issue was resolved. Turns out that Jquery validation treats "title" attribute as an error message under certain conditions :)

<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12">

<input title="this is a test tool tip." class="form-control"

data-val="true"

data-val-number="Must be a valid number"

data-val-regex="Invalid pattern."

data-val-regex-pattern="^-?\d{1,5}(\.\d{1,5})?$"

data_val_length="The field must be a string with a maximum length of 12."

data_val_length_max="12"

id="inputItem"

name="inputItem" type="number" value="">

<span class="field-validation-valid" data-valmsg-for="inputItem" data-valmsg-replace="true"></span>

</div>