Freigeben über


Writing Tests for HealthVault Applications

We have added some useful new functionality designed to make it easier to test a HealthVault application.

The existing HealthVault SDKs didn’t make it easy if you wanted to write isolated (or method-level) unit tests for features that talked to the HealthVault Platform. You could usually do it by designing your own layer that could return simulated results (sometimes called “mocking” in agile methodologies), but that was sometimes difficult because of the way the SDK worked.

In this release, we’ve made some changes that should make this a whole lot easier.

For the sake of discussion, consider a bit of application code that fetches medications from HealthVault and filters them:

          HealthRecordItemCollection GetNewMedications(HealthRecordAccessor record)
          {
              HealthRecordSearcher searcher = record.CreateSearcher(Medication.TypeId);
              HealthRecordItemCollection items = searcher.GetMatchingItems()[0];
              // filter items here... 
  
              return  items;
          }
  

We want to write a test that verifies that the “filter items here” part of the method works correctly, and we’d like the test to run without talking to the HealthVault platform. That’s not easy to do in the current SDK, because there’s no way to control what comes back from GetMatchingItems().

In the new SDK, there is a way to do that. If we debug down we will find that the call to GetMatchingItems ends up in the following method in a new class named HealthVaultPlatform.

 

          public  static  ReadOnlyCollection <HealthRecordItemCollection > GetMatchingItems(
              ApplicationConnection  connection,
              HealthRecordAccessor  accessor,
              HealthRecordSearcher  searcher)
          {
              return  HealthVaultPlatformItem .Current.GetMatchingItems(connection, accessor, searcher);
          }
  

The HealthVaultPlatform class centralizes all operations (except for one exception I’ll cover later) in a single class – if the SDK needs to talk to HealthVault it goes through that class. You can call into that class directly if you wish, or just troll through to see what operations can be performed.

To create our test, we are going to be hooking in underneath that level. The method above just forwards into a method in the HealthVaultPlatformItem class, and that class provides a way for us to override the behavior.

To get started, we need to create a class that derives from HealthVaultPlatformItem and overrides the GetMatchingItems() method. The first version looks like this:

      public  class  HealthVaultPlatformItemMock  : HealthVaultPlatformItem
      {
          HealthRecordItemCollection _itemsToReturn;
  
          public  HealthVaultPlatformItemMock(params  HealthRecordItem[] items)
          {
              _itemsToReturn = new  HealthRecordItemCollection(items);
          }
  
          public  override  ReadOnlyCollection <HealthRecordItemCollection> GetMatchingItems(
              ApplicationConnection connection, 
              HealthRecordAccessor accessor, 
              HealthRecordSearcher searcher)
          {
              List <HealthRecordItemCollection> collections = 
                  new List <HealthRecordItemCollection>();
              collections.Add(_itemsToReturn);
  
              return  new  ReadOnlyCollection <HealthRecordItemCollection>(collections);
          }
      }
  

We can use it like this (this is an NUnit test):

          [Test]
          public  void  GetMatchingItems()
          {
              Medication medication = new  Medication(new  CodableValue("Ibuprofen" ));
              Medication medication2 = new  Medication(new  CodableValue("Vitamin C" ));
  
              HealthRecordItemCollection newItems = null ;
              HealthVaultPlatformItemMock mock = new  HealthVaultPlatformItemMock(medication, medication2);
              HealthVaultPlatformItem.EnableMock(mock);
              ApplicationConnection connection = new  ApplicationConnection(Guid .NewGuid());
              HealthRecordAccessor accessor = new  HealthRecordAccessor(connection, Guid .NewGuid());
              newItems = GetNewMedications(accessor);
              HealthVaultPlatformItem.DisableMock(mock);
  
              Assert.AreEqual(2, newItems.Count);
              Assert.AreEqual("Ibuprofen" , ((Medication)newItems[0]).Name.Text);
              Assert.AreEqual("Vitamin C" , ((Medication)newItems[1]).Name.Text);
          }
  

When the call to GetMatchingItems() gets down to HealthVaultPlatformItems, it will end up calling our mocked method rather than the built-in one.

The code requires us to do a few things:

  1. Create an instance of the mock class.
  2. Enable the mock.
  3. Disable the mock.

We can make it nicer by having the mock class itself handle enabling and disabling the mock, using the following:

      public  class  HealthVaultPlatformItemMock  : HealthVaultPlatformItem, IDisposable 
      {
          HealthRecordItemCollection _itemsToReturn;
  
          public  HealthVaultPlatformItemMock(params  HealthRecordItem[] items)
          {
              _itemsToReturn = new  HealthRecordItemCollection(items);
              HealthVaultPlatformItem.EnableMock(this );
          }
  
          public  override  ReadOnlyCollection <HealthRecordItemCollection> GetMatchingItems(
              ApplicationConnection connection, 
              HealthRecordAccessor accessor, 
              HealthRecordSearcher searcher)
          {
              List <HealthRecordItemCollection> collections = new  List <HealthRecordItemCollection>();
              collections.Add(_itemsToReturn);
  
              return  new  ReadOnlyCollection <HealthRecordItemCollection>(collections);
          }
  
          #region  IDisposable
          ~HealthVaultPlatformItemMock()
          {
              Dispose(false );
          }
  
          /// <summary> 
          /// Disposes the request. 
          /// </summary> 
          ///  
          public  void  Dispose()
          {
              Dispose(true );
              GC.SuppressFinalize(this );
          }
  
          /// <summary> 
          /// Disables the mocking. 
          /// </summary> 
          ///  
          /// <param name="disposing"></param> 
          ///  
          protected  void  Dispose(bool  disposing)
          {
              HealthVaultPlatformItem.DisableMock();
          }
  
          #endregion  IDisposable
   
      }
  
 That allows us to simplify our test code to this:
  
          [Test]
          public  void  GetMatchingItems()
          {
              Medication medication = new  Medication(new  CodableValue("Ibuprofen" ));
              Medication medication2 = new  Medication(new  CodableValue("Vitamin C" ));
  
              HealthRecordItemCollection newItems = null ;
              using  (HealthVaultPlatformItemMock mock = new HealthVaultPlatformItemMock(medication, medication2))
              {
                  ApplicationConnection connection = new  ApplicationConnection(Guid .NewGuid());
                  HealthRecordAccessor accessor = new  HealthRecordAccessor(connection, Guid .NewGuid());
                  newItems = GetNewMedications(accessor);
              }
  
              Assert.AreEqual(2, newItems.Count);
              Assert.AreEqual("Ibuprofen" , ((Medication) newItems[0]).Name.Text);
              Assert.AreEqual("Vitamin C" , ((Medication) newItems[1]).Name.Text);
          }
  

Special Classes

There are a few classes where it’s not straightforward to create the class. For classes such as ServiceInfo, we don’t provide a way to create and modify them directly. To create an instance of those classes, you need to derive a new class and use that:

      public  class  ServiceInfoTest  : ServiceInfo
      {
          public  ServiceInfoTest(string  version)
          {
              Version  = version;
          }
      }
  

and the associated test uses this class instead of ServiceInfo:

          [Test]
          public  void  GetServiceInfoTest()
          {
              ApplicationConnection connection = new  ApplicationConnection(Guid .NewGuid());
  
              ServiceInfoTest serviceInfo = new  ServiceInfoTest("V2.x" );
  
              ServiceInfo serviceInfoBack = null ;
              using  (HealthVaultPlatformInformationMock mock = new  HealthVaultPlatformInformationMock(serviceInfo))
              {
                  serviceInfoBack = connection.GetServiceDefinition();
              }
  
              Assert.AreEqual("V2.x" , serviceInfoBack.Version);
          }
  

 

Limitations

We currently don’t have mockable interfaces for blob operations. We hope to do that in a future release.