Unit Testing Dynamic XAP Files

By now, you probably are aware that you can dynamically load XAP files using the Managed Extensibility Framework (MEF) within your Silverlight applications. Have you been scratching your head, however, and wondering how on earth you would actually test something like that?

It is possible, and here’s a quick post to show one way you can.

First, we need a decent deployment service. You’re not really going to hard-code the download and management, are you? I didn’t think so. If you need an example, look no further than the sample code I posted to Advanced Silverlight Applications using MEF. Here’s what the interface looks like:

public interface IDeploymentService
{
    void RequestXap(string xapName, Action<Exception> xapLoaded);       
       
    AggregateCatalog Catalog { get; }
}

This keeps it simple. Request the xap file, then specify a delegate for a callback. You’ll either get a null exception object (it was successful) or a non-null (uh… oh.)

Now, let’s focus on testing it using the Silverlight Unit Testing Framework. The first caveat is that you cannot use it on the file system. This means that your project will not work if you run it with a test page rather than hooking it to a web server (local or not).

Doing this is simple. In your ASP.NET project, go to the Silverlight tab and add your test project. When you are adding it, there is an option to generate a test page. I typically have one “test” web project with all of my test Silverlight applications, so I will have multiple test pages. To run a particular test, you simply set your ASP.NET web project as the start up project, then the corresponding test page (we’re talking the aspx, not the html) as the start page. I usually delete the automatically generated HTML pages.

Now we need to give MEF a test container. The caveat here is that, without a lot of work, it’s not straightforward to reconfigure the host container so you’ll want to make sure you test a given dynamic XAP file only once, because once it’s loaded, it’s loaded.

This is what my application object ends up looking like:

public partial class App
{
    public AggregateCatalog TestCatalog { get; private set; }

    public App()
    {
        Startup += Application_Startup;            
        InitializeComponent();
    }

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // set up a catalog for tests
        TestCatalog = new AggregateCatalog();
        TestCatalog.Catalogs.Add(new DeploymentCatalog());

        var container = new CompositionContainer(TestCatalog);

        CompositionHost.Initialize(container);

        // now set up the unit testing framework
        var settings = UnitTestSystem.CreateDefaultSettings();
        RootVisual = UnitTestSystem.CreateTestPage(settings);
    }              
}

Here, I haven’t composed anything, just set up the container.

Now I’m going to add a simple dynamic XAP for testing. I add a new Silverlight application and wire it to the test web site but do NOT generate a test page. I blow away the App.xaml and MainPage.xaml resources, and add a simple class called Exports. Here is my class:

public class Exports
{
    private const string TESTTEXT = "TestText";

    [Export(TESTTEXT, typeof(string))]
    public string TestText { get { return TESTTEXT; } }
}

Yes, you got it – just a simple export of a string value. Now let’s write our test. I create a new test class and decorate it with the TestClass attribute. I am also running asynchronous tests, so it’s best to inherit the test from SilverlightTest which has some base methods for asynchronous testing.

Let’s take a look at the set up for my test:

[TestClass]
    public class DeploymentServiceTest : SilverlightTest
    {
        private const string DYNAMIC_XAP = "DynamicXap.xap";
        private const string TESTTEXT = "TestText";

        private DeploymentService _target;
    
        [Import(TESTTEXT, AllowDefault = true, AllowRecomposition = true)]
        public string TestString { get; set; }
     
        public DeploymentServiceTest()
        {
            CompositionInitializer.SatisfyImports(this);
        }

        [TestInitialize]
        public void TestInit()
        {
            if (Application.Current.Host.Source.Scheme.Contains("file"))
            {
                _target = null;
            }
            else
            {
                _target = new DeploymentService();
                ((App) Application.Current).TestCatalog.Catalogs.Add(_target.Catalog);
            }
        }
}

So right now I’m simply setting up my targets. The property is key – by composing imports on construction, I register my test class with the MEF system. Right now, however, I haven’t loaded anything, so it won’t be able to satisfy the import. By using AllowDefault true, however, I tell it I’m expecting something later and setting it to null is fine. The recomposition is what will trigger an update once the catalogs change. I also reach out to the test catalog I set up in the main application and add the catalog from my deployment service to it. Note that if I am running on the file system, I don’t bother setting up my service.

Next, I can add a stub to determine if I can even test this. If I am running from the file system, the deployment service is never set up. I created a helpful method that asserts an “inconclusive” when this is the case:

private bool _CheckWeb()
{
    if (_target == null)
    {
        Assert.Inconclusive("Cannot test deployment service from a test page. Must be hosted in web.");
        return false;
    }

    return true;
}        

Now we can write our main test. First, we check to make sure we are in a web context. Then, we load the xap, and once it is loaded, confirm there were no errors and that our property was successfully set:

[Asynchronous]
[TestMethod]
public void TestValidXap()
{
    if (!_CheckWeb())
    {
        return;
    }

    Assert.IsTrue(string.IsNullOrEmpty(TestString), "Test string should be null or empty at start of test.");
    _target.RequestXap(DYNAMIC_XAP, exception =>
                                        {
                                            Assert.IsNull(exception, "Test failed: exception returned.");
                                            Assert.IsFalse(string.IsNullOrEmpty(TestString),
                                                            "Test failed: string was not populated.");
                                            Assert.AreEqual(TESTTEXT, TestString,
                                                            "Test failed: property does not match.");
            }
}

And that’s pretty much all there is to it – of course, I am also adding checks for things like contract validation (are you passing me a valid xap name?) and managing duplicates, but you get the picture.

Jeremy Likness

Deploy Your Equipment Locally and Globally

For the better part of a decade, Atmosera has owned, operated, and offered TYPE-II SSAE 16 compliant data centers to clients who need secure space, power, and cooling to deploy their mission critical applications. We also leverage 21 additional data centers in the U.S. and abroad through strategic alliances. We offer a range of options from racks and full cabinets to secure cages. We also have network connectivity from several service providers.
Clients benefit from multiple hardened layers of security, reliability, and protection, combined with rigorous operational and maintenance procedures. We provide professional services that include remote hands, monitoring, and backup. We operate three data centers in the Portland Metropolitan area: Data Center 1 (DC1) and Data Center 2 (DC2) located in Beaverton, and Data Center 3 (DC3) located downtown Portland.

Electrical Power Systems

In the unlikely event of failure, Atmosera’s power systems are designed to run uninterrupted. We have dedicated PGE (Portland General Electric) 1500kVA Clean Wind℠ electrical service into dual 300kVA CleanSource® UPS systems with efficient flywheel energy storage plus dual battery- powered 300kVA UPS systems. The UPS systems are configured 2N and are backed up by three independent diesel generators with a combined capacity of 1400kVA. The generators are exercised every month for 60 minutes under load.

Primary and Secondary Electrical Power Systems

Power to the data center is provided by a 2N system. Primary power is provided by Portland General Electric (PGE) through a dedicated 1500kVA 3-phase 277/480VAC transformer and power feed.

There are two secondary systems: A and B. Either the A or B system is capable of running the full load and half of the air conditioning systems. The A and B systems have independent transfer switches, Uninterruptible Power Supplies (UPSs) and power distribution. UPS and mechanical power loads have independent transfer switches.

Power Switching

Automatic Transfer Switches (ATSs) connect the primary and secondary power systems to the data center load. In the event of a power or phase loss, the ATSs detect the anomaly, start the generators and transfer the load. Generators are on-line, with load, within 10 seconds. Ten minutes after stable primary power is restored and stable, the ATSs transfer the load back to primary power.

Annunciator panels in the Command Center monitors ATS switching conditions. The ATSs are automatically tested under load every other week as part of the generator exercise schedule.

Power to the Cabinets

Full- and half-sized cabinets in Data Center 1 have dual power feeds. One-third and smaller cabinets have a single power feed. Default power configurations include:

  • Full cabinet, 30”, 34”, and 39” deep: 2×20 Amp. (power configurations available up to redundant three-phase 30 Amp, 208 V)
  • 1/2 cabinet, 30” deep: 1×20 Amp or 2×10 Amp. (Power configuration is cabinet- specific.)
  • 1/3 cabinet, 39” deep: 1×20 Amp or 2×20 Amp. and 30” deep: 1×10 Amp.
  • 1/4 cabinet, 30” deep and Super Condo, 30” or 39” deep: 1×7 Amp.
  • Condo. 30” deep: 1×4 Amp.

HVAC and Mechanical

Cooling is provided by Liebert 30 ton AC systems. A hot/cold aisle containment system saves energy and improves cooling efficiencies.

Networking and Telecommunications

Atmosera is a carrier-neutral facility with multiple providers, including AboveNet, CenturyLink, Level 3, Comcast, Freewire Broadband, Frontier, Integra, LS Networks and Time Warner.

Atmosera is a founding member of the Northwest Access Exchange (NWAX), a regional Internet exchange with a Point of Presence (PoP) at Atmosera. NWAX provides peering and transit services over a gigabit Ethernet fabric, and interconnects nearly 20 major ISP, business and public/education networks, providing the highest possible performance with local peers.

Three Tier 1 providers — Level 3, AboveNet and CenturyLink — deliver upstream Internet bandwidth capacity on GigE fiber.

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X