2011-11-02

Silverlight Unit Testing: TestInitialize/TestCleanup methods do not fire, tests do not run, nor pass/fail, and no details given

I had the classic bang-head-against-the-keyboard for three hours scenario today while doing Silverlight Unit Testing.

I had a test class with two unit tests in them which worked fine, until I started refactoring to get common setup/teardown functionality moved into methods with TestInitialize/TestCleanup attributes applied.

Then the weirdness started.  I started seeing this:
The tests don't run; don't pass or fail; and no details as to why.
Check out the yellow highlighted areas.
As you can see, there wasn't a whole lot of information present to assist me in my predicament.  After removing the TestInitialize/TestCleanup attributes, the tests worked fine.

I began searching the internet trying to find someone who ran into the same problem.  I found many results where developers complained of the TestInitialize methods swallowing exceptions and moving on, so I started down that path in my own code, trying to discover if there was an exception I was missing that was being eaten and causing the entire class to fail.

The only problem was, when I commented all code within the bodies of the TestInitialize/TestCleanup methods, I still ended up with the same results.
???
Digging deeper, it finally dawned on me that the test class in question was inheriting from a base test class that also happened to have methods dressed with the TestInitialize/TestCleanup attributes.  Looking at the declaration of TestInitializeAttribute revealed what I suspected:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public sealed class TestInitializeAttribute : Attribute

AllowMultiple = false... which makes sense. So my code had two problems:

  1. My base class' method for TestInitialize needed to be made virtual so it could be overridden in classes that inherit from it to allow for overriding (and calling back to the base so both get their jobs done.)
  2. My child class' method was named different, so I needed to go make it match and override.
Once I fixed these problems for both the init and cleanup methods, the tests went back to working accurately.

Bottom Line: When doing unit testing with base test classes that perform common setup functionality, make sure to have your Setup/Teardown or Initialize/Cleanup methods marked virtual in the base class, so they can be overridden in the sub-classes.  Then override those methods in the sub-class, making sure to call back to the base appropriately.

Example (MSTest):

public class CommonTestSetupBase { [TestInitialize] public virtual void TestSetup() { // do common setup work for all that inherit } [TestCleanup] public virtual void TestTeardown() { // do common cleanup work for all that inherit } } //================= [TestClass] public class UnitTestedClassTests : CommonTestSetupBase { [TestInitialize] public override void TestSetup() { base.TestSetup(); // do common setup for this class } [TestCleanup] public override void TestTeardown() { // do common cleanup for this class base.TestTeardown(); } } I knew I wouldn't remember this if I bump into it again, so I had to document it here... I wish I had more time to go into more detail, but I hope this will be enough to help you and I in the future when we meet this problem again.

2011-08-30

Silverlight throws InvalidOperationException with Common_MethodFailed error when calling HtmlElement.SetAttribute for the "type" attribute

I was working on a Silverlight application the other day and needed to create and submit an HTML form to another ASPX page inside the website hosting the app.

To accomplish this, I was using the HtmlDocument.CreateElement, HtmlElement.SetAttribute and HtmlElement.AppendChild methods to set the whole thing up.

After deploying the application having success with Internet Explorer 9 (IE9), Chrome, etc. we tested on two virtual machines that had IE7 and IE8 and were met with errors and no form submission.

It turns out it was because I was trying to set the "type" attribute of the <input /> elements I was creating with the Silverlight methods after I'd called the AppendChild method.

IE7 and IE8 don't like a developer setting the "type" attribute after the element has been appended to the document and it will throw a JavaScript error which bubbles up to the Silverlight application and the user is shown an obscure InvalidOperationException error whose key is "Common_MethodFailed".

It made no sense to me, but I dug deeper until I could find the offending line.  I then tried an experiment with a XHTML/JavaScript page in the offending browsers to see if it was a Silverlight problem or a problem with the JavaScript engines of said browsers.

I ran into the same problem without Silverlight in the equation.  I wrote up a detailed article explaining it and have the experiment to try in different browsers yourself on my JavaScript Jedi website.

The problem can be solved by making sure you call AppendChild AFTER you set up all the properties/attributes on the HtmlElement, not before.

I hope this helps you avoid several hours of frustration.  :)
Happy Coding!

2011-06-17

WCF "Gotcha" When Sending an Invalid Enum Value Across the Boundary

The Silverlight application I'm working on for my employer at the time of this writing involves WCF services that provide data for the app.

It was working fine until a coworker ran a SQL query that changed an int field (which maps to an Enum in our code) to an invalid value on several records in a common test database a few of us were pointing to.

All of the sudden we were getting a FaultException (I can't remember the exact error - but it was one of those unrelated ones that mask the real exception message that caused the problem to begin with.) while trying to load a graph.

Further investigation revealed that our asynchronous calls to the WCF service client were retrying the same call three times and coming back with a failure.  Stepping down deeper into the code, we saw that our resultset seemed to be coming back fine from our data layer, leaving us wondering why it was behaving so strange.

My coworker put a breakpoint where our data layer returns the IEnumerable to the service so it can serialize/return the data to our app, and changed the resultset to an empty array of the given type instead of allowing the real resultset through.

Only a single attempt was made on the service instead of three and the data was received fine by the application...  However, when we reverted to allow the regular resultset through, it again made three attempts and returned the exception.

On the next run, we decided to look at the resultset closer in the QuickWatch window.  We didn't look carefully enough because everything looked correct... so we started removing one object at a time until we could prove that the culprit was corrupt data in our resultset.

Finally we expanded two objects in our collection at the same time in the QuickWatch window and started comparing.  We noticed that one instance's enum property was retuning the name of the assigned enum and another showed an integer value.

After asking why that would happen, it dawned on me that it must be an invalid enum value and therefore couldn't resolve to a name when ToString() was called.  I assume to fail gracefully, Microsoft had their Enum.ToString() try to do name first and just fall back to the value of the Enum's base type if it couldn't resolve the name, rather than throwing an Exception.

Examining the implementation of the enum quickly confirmed the suspicion.  After probing other coworkers, we discovered the erroneous query that had been run against the database.  :)

I assume what happens is an exception occurs when the WCF tries to serialize the object to send across the boundary... but the exception is swallowed up and the Fault Exception with the less-than-helpful error message is returned to the consumer of the service.

Moral of the story: Be careful when using Enums that map to data in your database.  Make sure they always match the allowed values in the database (which is easy to do if you have look-up tables and use an ORM (like PLINQO, etc.) to generate the enums for you. 

Also, if you use "switch" statements in your code on the enum value, make sure your default case handles an invalid enum value scenario.  For instance, you've made a switch statement that contains a case block for all valid enum values.  Your default case can throw an ArgumentOutOfRangeException so you can quickly detect when something like that happens.

This will be harder to detect in scenarios like the one I described above, because the code is still "valid" at compile and runtime until the sucker is serialized.  I don't know what the best practice solution is for that scenario, but I do know I want a better FaultException passed to me if serialization breaks before being passed from the WCF service.

Guess I have my work cut out for me tomorrow.

For those like me that have a hard time visualizing what I'm talking about... here's a contrived example.

public enum ReportType
{
  Html = 1,
  Excel = 2,
  Pdf = 3
}

The query to the database changed the offending records to 0, 4 or some other number that wasn't the valid values.  (Incidentally, my coworker really meant to change another int field's value... but ended up typing the wrong column name.)   Too funny.

And now you know... go forth and make sure you aren't bit by this problem.

Silverlight and Unit Testing - Reference Gotcha When Testing View Code

I'm new to Silverlight and am still learning my way around various nuances of the platform.

I like it so far and have been learning a lot. When a recent check-in was made by a co-worker to our project at work, we had around 90 of over 800 unit tests broken with this error in each of them:
The attachable property 'TransitionEffect' was not found in type 'ExtendedVisualStateManager'.

Being new to XAML, I had no idea where to start, except to go find the .xaml files resource dictionaries to try to figure out what the problem was.  Searching the internet made it sound like I had x:Name attributes with the same values from different dependent XAML files.

I should mention I was working in a UserControl XAML file to begin with, and started searching up the dependency hierarchy to see if the naming problem was the real issue.

The XAML files were quite large, so finding all the x:Name attributes and comparing them was going to take a while.  I opted to approach this using LINQPad.  I replaced quotes with double-quotes in the XAML so I could bring it into LINQPad as a string constant and loaded it into a XDocument object; using LINQ to XML to find matches from the other file's XAML for me.  After discovering one, I fixed it and re-ran my unit tests.  I still got the same error.

What I didn't understand was that the application ran fine and the effect was working... why on earth wouldn't it work in our unit tests?  It should have dawned on me that both the application project and the unit test project required the appropriate DLLs to be referenced in order for that namespace to be available.

Sure enough, the application project had them but the unit test project did not.  As soon as I added the references, the tests passed with flying colors again.

The required references, for those that get the exact same error:
Microsoft.Expression.Effects
Microsoft.Expression.Interactions
(both part of the Silverlight v4.0 Toolkit)

Moral of the story: When you add references to your application project, make sure you add them to the corresponding unit test project if necessary as well.

Now the next question... Why was I required to have those when I wasn't rendering any UI, but merely using the View classes in the unit test?  It seemed as if the XAML was still being parsed.

This makes sense, being as your View classes are declared as partial and the other piece to this partial puzzle is the XAML file.  Remember that whenever the View class is constructed, the InitializeComponent method is called, which parses the XAML and sets up everything declared there (correct me if I'm not describing that accurately!)

That said, if you're going to unit test a view file, you have to make sure that anything required by the XAML files are also referenced.  It's easy to take care of that for the C# files because you get compile-time errors, but you don't necessarily with the declarative XAML files.  A drawback, but one that can be handled if we're aware.

Bottom line... remember that both the XAML and corresponding C# file make up your View class and both files' reference requirements must be met to ensure all namespaces/code are available for your unit tests.

I hope this will save you (and myself) a lot of time in the future if I ever encounter this problem again.