Friday, August 28, 2015

Proper karma-ng-html2js-preprocessor Setup

If you want to test directives in AngularJS, using Karma, and those directives use external templates, you'll have to use the karma-ng-html2js-preprocessor plugin for Karma.  It took me a few tries to get it right so hopefully these instructions help somebody (even if it's me) down the road.

 The first thing you'll want to do is install the preprocessor through npm using this command: npm install karma-ng-html2js-preprocessor.  You can use the -g switch to install it globally, or not.

Once you have it installed, you'll need to update your Karma config file to pull it in and use it, and that's where my first issue came about.  First, include the preprocessor in the plugins section of the config:

   1:  plugins: [
   2:      'karma-phantomJS-launcher',
   3:      'karma-jasmine',
   4:      'karma-ng-html2js-preprocessor',
   5:      'karma-coverage'
   6:  ],

The next thing you'll need to do is setup the preprocess to pull in your html files:

   1:  preprocessors: {
   2:      './Templates/*.html': ['ng-html2js'],
   3:      './Content/Controls/*.html': ['ng-html2js']
   4:  }

Now, you can't forget to do the next thing, which is to include your html files in your list of files:

   1:  files: [
   2:      'Templates/*.html',
   3:      'Content/Controls/*.html'
   4:  ]

If you don't do that part, the templates won't be imported by the preprocessor and your tests will fail.

You can configure the preprocessor if you need to, and you may have to.  I'm not gonna lie here: I don't know how to configure this completely.  I know what I had to do to get everything to work and that's what I'm sharing here.  If you want more details on the configuration options, check out the Github page for the preprocessor.

In our solution we use the forward slash to reference our external templates.  In the directive, the templateUrl may look like this: /templates/sample.html.  Karma won't automatically know to do that (I think this has to do with the way the web server is started and the way the browser finds the "root" of the application, but I'm not 100% on that).  What we have to do to make this work is prepend the templates with a forward slash.  Easy enough once you know it needs to be done:

   1:  ngHtml2JsPreprocessor: {
   2:      // setting this option will create only a single module that contains templates
   3:      // from all the files, so you can load them all with module('foo')
   4:      moduleName: 'templates',
   5:      // since our templateUrls have to be prefixed with a forward slash in order for them to be found during normal rendering
   6:      // we need to prefix the them with the forward slash so karma can find them and the preprocessor can cache them with
   7:      // the forward slash
   8:      prependPrefix: '/'
   9:  }

There's also an option to stripPrefix, but as you can see I didn't have to use that one.  The point here is to be aware that you can configure the preprocessor and it can be confusing when you try to do it so play with it for a while.  If I can find the blog that put me on the right track, I'll throw up a link to it.

Bonus: If you need to see what's going on while you're trying to figure this out, you can change the log level (and therefore the verbosity of the logging) by finding the logLevel section in the Karma config and changing it to config.LOG_DEBUG.  That's how I figured out my issues with prependPrefix.

Second Bonus: If you need even more logging than that, you can hack away on the logging module itself.  Since everything in node.js (AFAIK) is JavaScript, you can make changes on the fly and watch the enhanced output.  To do that, just find the logger JavaScript file and start making changes to it.  Rerun your tests to see the modified output.

Monday, August 24, 2015

Setup VS for "Integrated" Karma Testing

If you're at all interested in unit testing your JavaScript, specifically your AngularJS areas, you may be using Karma and Jasmine.  If you're like me and you do most of your coding in Visual Studio you might wish there was some integration to be had between VS and your Karma tests.  Good news, there is!  Sort of.

There's an extension you can install that will reroute the output from Karma to your Output window in Visual Studio.  It's not the best way to integrate, but it definitely works as long as you get it all set up properly.  Hopefully these instructions get you there.
  1. Download the extension from here and install it
  2. Make sure your Karma config file is named karma.unit.conf.js (or karma.e2e.conf.js) and is saved at the root of your project (seriously, you can't put it anywhere else or name it anything else or it won't work)
  3. Everything else is standard for Karma so there shouldn't be any other setup necessary specifically for this extension
The extension will run your tests every time you launch the solution, and you can toggle it on and off by going to Tools > Enable/disable Karma unit testing...

The only other caveat is that in your Output window you'll need to make sure the "Show output from:" dropdown is set to Karma.

Custom Config Sections

Sometimes when you're developing a small application (or I suppose it could be a large application) you'll find that you wish the app.config/web.config had some additional options.  Coincidentally, that exact scenario arose for me recently.  I'm writing a small console application to combine reports for three different types of code coverage.  One of the reporting tools I'm using is OpenCover, which allows you to specify - through the use of command line arguments - which assemblies to check when running.  I wanted to set something up in my config file to allow me to specify this information, so I needed some custom configuration nodes.

I started by reading through this blog, which was very informative, but didn't totally do what I needed it to do.  I extended that example to meet my needs, and this is what I ended up with:
   1:  <configSections>
   2:      <section name="AssemblySettings" type="UnitTestCoverage.ConfigurationExtensions.AssemblySettings, UnitTestCoverage.ConfigurationExtensions"/>
   3:      <section name="FilterSettings" type="UnitTestCoverage.ConfigurationExtensions.FilterSettings, UnitTestCoverage.ConfigurationExtensions"/>
   4:  </configSections>
   5:  <appSettings>...snipped...</appSettings>
   6:  <AssemblySettings>
   7:      <Assemblies>
   8:          <clear />
   9:          <add key="SomeProject.Test" value="C:\Dev\SomeProject.Test\bin\Debug\SomeProject.Test.dll" outputDirectory="C:\Output\SomeProject.Test\" outputFile="SomeProject.Test.xml">
  10:              <filters>
  11:                  <clear />
  12:                  <add key="FirstName" value="[FirstNamespace]SomeProject.FirstNamespace.*" type="Include" />
  13:                  <add key="SecondName" value="[SecondNamespace]SomeProject.SecondNamespace.*" type="Include" />
  14:                  <add key="Test" value="[SomeProject.Test]" type="Ignore" />
  15:              </filters>
  16:          </add>
  17:          <add key="SomeOtherProject.Test" value="C:\Dev\SomeOtherProject.Test\bin\Debug\SomeOtherProject.Test.dll" outputDirectory="C:\Output\SomeOtherProject.Test\" outputFile="SomeOtherProject.Test.xml">
  18:              <filters>
  19:                  <clear />
  20:                  <add key="SomeOtherProject" value="[SomeOtherNamespace]*" type="Include" />
  21:                  <add key="SomeOtherProjectTest" value="[SomeOtherNamespace.Test]*" type="Ignore" />
  22:              </filters>
  23:          </add>
  24:      </Assemblies>
  25:  </AssemblySettings>

So how did I do that?  I'd love to show you.  To get what I have above, I had to create five new objects in my solution.  I decided to keep this part separate from my business logic by creating a ConfigurationExtensions project to hold everything.  You don't have to do that, of course, but I found it to be easiest.  The first class I created was the AssemblySettings class, which inherits from System.Configuration.ConfigurationSection and corresponds to
<AssemblySettings>
up there.
   1:  public class AssemblySettings : ConfigurationSection
   2:  {
   3:      [ConfigurationProperty("Assemblies", IsDefaultCollection = false)]
   4:      [ConfigurationCollection(typeof(AssemblyCollection), AddItemName = "add", RemoveItemName = "remove",
   5:          ClearItemsName = "clear")]
   6:      public AssemblyCollection Assemblies
   7:      {
   8:          get
   9:          {
  10:              AssemblyCollection assemblyCollection = (AssemblyCollection)base["Assemblies"];
  11:              return assemblyCollection;
  12:          }
  13:      }
  14:  }

The next class is AssemblyCollection (which you may have noticed is referenced on line 4 of AssemblySettings). This class inherits from ConfigurationElementCollection and it doesn't have a direct partner in the web.config. However, this is the class that allows me to have multiple Assembly items in the web.config so it is very important.
   1:  public class AssemblyCollection : ConfigurationElementCollection
   2:  {
   3:      public override ConfigurationElementCollectionType CollectionType
   4:      {
   5:          get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
   6:      }
   7:   
   8:      protected override ConfigurationElement CreateNewElement()
   9:      {
  10:          return new AssemblyElement();
  11:      }
  12:   
  13:      protected override object GetElementKey(ConfigurationElement element)
  14:      {
  15:          return ((AssemblyElement)element).Key;
  16:      }
  17:   
  18:      public AssemblyElement this[int index]
  19:      {
  20:          get { return (AssemblyElement)BaseGet(index); }
  21:          set
  22:          {
  23:              if (BaseGet(index) != null)
  24:              {
  25:                  BaseRemoveAt(index);
  26:              }
  27:              BaseAdd(index, value);
  28:          }
  29:      }
  30:   
  31:      new public AssemblyElement this[string Name]
  32:      {
  33:          get { return (AssemblyElement)BaseGet(Name); }
  34:      }
  35:   
  36:      public int IndexOf(AssemblyElement assembly)
  37:      {
  38:          return BaseIndexOf(assembly);
  39:      }
  40:   
  41:      public void Add(AssemblyElement assembly)
  42:      {
  43:          BaseAdd(assembly);
  44:      }
  45:   
  46:      protected override void BaseAdd(ConfigurationElement element)
  47:      {
  48:          BaseAdd(element, false);
  49:      }
  50:   
  51:      public void Remove(AssemblyElement assembly)
  52:      {
  53:          if (BaseIndexOf(assembly) >= 0)
  54:          {
  55:              BaseRemove(assembly.Key);
  56:          }
  57:      }
  58:   
  59:      public void RemoveAt(int index)
  60:      {
  61:          BaseRemoveAt(index);
  62:      }
  63:   
  64:      public void Remove(string name)
  65:      {
  66:          BaseRemove(name);
  67:      }
  68:   
  69:      public void Clear()
  70:      {
  71:          BaseClear();
  72:      }
  73:  }

The last Assembly related class is AssemblyElement, which inherits from ConfigurationElement.
   1:  public class AssemblyElement : ConfigurationElement
   2:  {
   3:      public AssemblyElement(string key, string value, string outputDirectory, string outputFile)
   4:      {
   5:          Key = key;
   6:          Value = value;
   7:          OutputDirectory = outputDirectory;
   8:          OutputFile = outputFile;
   9:      }
  10:   
  11:      public AssemblyElement()
  12:          : this("", @"SomeValue.dll", @"C:\Output\", "results.xml")
  13:      {
  14:      }
  15:   
  16:      [ConfigurationProperty("key", DefaultValue = "", IsRequired = true, IsKey = true)]
  17:      public string Key
  18:      {
  19:          get { return (string)this["key"]; }
  20:          set { this["key"] = value; }
  21:      }
  22:   
  23:      [ConfigurationProperty("value", DefaultValue = "", IsRequired = true)]
  24:      public string Value
  25:      {
  26:          get { return (string)this["value"]; }
  27:          set { this["value"] = value; }
  28:      }
  29:   
  30:      [ConfigurationProperty("noshadow", DefaultValue = "true", IsRequired = false)]
  31:      public bool NoShadow
  32:      {
  33:          get { return (bool) this["noshadow"]; }
  34:          set { this["noshadow"] = value; }
  35:      }
  36:   
  37:      [ConfigurationProperty("outputFile", DefaultValue = @"results.xml", IsRequired = true)]
  38:      public string OutputFile
  39:      {
  40:          get { return (string)this["outputFile"]; }
  41:          set { this["outputFile"] = value; }
  42:      }
  43:   
  44:      [ConfigurationProperty("outputDirectory", DefaultValue = @"C:\Output\", IsRequired = true)]
  45:      public string OutputDirectory
  46:      {
  47:          get { return (string)this["outputDirectory"]; }
  48:          set { this["outputDirectory"] = value; }
  49:      }
  50:   
  51:      [ConfigurationProperty("filters")]
  52:      public FilterCollection Filters
  53:      {
  54:          get { return (FilterCollection)this["filters"]; }
  55:          set { this["filters"] = value; }
  56:      }
  57:  }

You can see in the config file (and in AssemblyElement) that we have a nested configuration for filters, that uses a new class called FilterCollection. FilterCollection inherits from ConfigurationElementCollection.
   1:  public class FilterCollection : ConfigurationElementCollection
   2:  {
   3:      public override ConfigurationElementCollectionType CollectionType
   4:      {
   5:          get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
   6:      }
   7:   
   8:      protected override ConfigurationElement CreateNewElement()
   9:      {
  10:          return new FilterElement();
  11:      }
  12:   
  13:      protected override object GetElementKey(ConfigurationElement element)
  14:      {
  15:          return ((FilterElement)element).Key;
  16:      }
  17:   
  18:      public FilterElement this[int index]
  19:      {
  20:          get { return (FilterElement)BaseGet(index); }
  21:          set
  22:          {
  23:              if (BaseGet(index) != null)
  24:              {
  25:                  BaseRemoveAt(index);
  26:              }
  27:              BaseAdd(index, value);
  28:          }
  29:      }
  30:   
  31:      new public FilterElement this[string Name]
  32:      {
  33:          get { return (FilterElement)BaseGet(Name); }
  34:      }
  35:   
  36:      public int IndexOf(FilterElement filter)
  37:      {
  38:          return BaseIndexOf(filter);
  39:      }
  40:   
  41:      public void Add(FilterElement filter)
  42:      {
  43:          BaseAdd(filter);
  44:      }
  45:   
  46:      protected override void BaseAdd(ConfigurationElement element)
  47:      {
  48:          BaseAdd(element, false);
  49:      }
  50:   
  51:      public void Remove(FilterElement filter)
  52:      {
  53:          if (BaseIndexOf(filter) >= 0)
  54:          {
  55:              BaseRemove(filter.Key);
  56:          }
  57:      }
  58:   
  59:      public void RemoveAt(int index)
  60:      {
  61:          BaseRemoveAt(index);
  62:      }
  63:   
  64:      public void Remove(string name)
  65:      {
  66:          BaseRemove(name);
  67:      }
  68:   
  69:      public void Clear()
  70:      {
  71:          BaseClear();
  72:      }
  73:  }

Since a FilterCollection is made up of individual filters, we'll have to create those as well. The FilterElement class inherits from ConfigurationElement.
   1:  public class FilterElement : ConfigurationElement
   2:  {
   3:      public FilterElement(string key, string type, string value)
   4:      {
   5:          Type = type;
   6:          Value = value;
   7:          Key = key;
   8:      }
   9:   
  10:      public FilterElement()
  11:          : this("Namespace", "Add", "[*]*")
  12:      {
  13:      }
  14:   
  15:      [ConfigurationProperty("key", DefaultValue = "", IsRequired = true, IsKey = true)]
  16:      public string Key
  17:      {
  18:          get { return (string)this["key"]; }
  19:          set { this["key"] = value; }
  20:      }
  21:   
  22:      [ConfigurationProperty("type", DefaultValue = "Add", IsRequired = true)]
  23:      public string Type
  24:      {
  25:          get { return (string)this["type"]; }
  26:          set { this["type"] = value; }
  27:      }
  28:   
  29:      [ConfigurationProperty("value", DefaultValue = "[*]*")]
  30:      public string Value
  31:      {
  32:          get { return (string)this["value"]; }
  33:          set { this["value"] = value; }
  34:      }
  35:  }

Monday, August 3, 2015

Unit Testing in SQL Server (Part 1)


I'm a huge advocate of unit testing your .NET code, but until recently I didn't really know it was possible to test your SQL stored procedures as well. Now I'm a huge advocate of testing those, too.  Hopefully at the end of this tutorial you'll have a solid understanding of how to use the tSQLt framework to write unit tests for your SQL code.

A couple of things to keep in mind as you consider writing unit tests for SQL:
  • It's really easy to over-test in SQL; much easier than in .NET because it's tempting to test for impossible scenarios. If scenarios are impossible (because of database constraints, business rules, or some other restriction), strongly consider whether you need to test them before diving in
  • Until I wrote unit tests I never considered writing stored procedures in the same way I write .NET code. I would write monolithic stored procedures instead of breaking them into reusable (and testable) pieces. It's a lot easier to test a bunch of small stored procedures than it is to test a single huge stored procedure
First I want to send you to the tSQLt website to get their rundown of this whole thing. You can check it out here.

Now that you've done that, let's get you squared away with the Northwind database. Yes, seriously. Don't look at me like that. Northwind has everything we need and it's still pretty small. It's perfect for this. You can download Northwind from here. That should have given you a backup file that you'll want to restore to a server somewhere. If you have SQLExpress installed that'll work just fine. Before you can run any tests, though, you need to run one command against the Northwind database after you restore it.

DECLARE @Command VARCHAR(MAX)


SELECT @Command = REPLACE(REPLACE@Command, '<<DatabaseName>>', sd.[name]), '<<LoginName>>', sl.[name])
FROM master..sysdatabases sd
INNER JOIN master..syslogins sl
    ON sd.[sid] = sl.[sid]
WHERE sd.[name] = DB_NAME()
Update: I went back and tried to follow these instructions and found that the above script no longer worked.  I'm leaving it here for historic purposes, but below is the script that I ran this time around.

DECLARE @User VARCHAR(50)


SELECT @User = QUOTENAME(sl.[name])
FROM master..sysdatabases sd
INNER JOIN master..syslogins sl
    ON sd.[sid] = sl.[sid]
WHERE sd.[name] = DB_NAME()

All that does is change the database so that you're the owner.

Update: I forgot to include a step here. You need to run the next bit of SQL before you run tSQLt.class.sql or it won't work properly. This is for SQL Server 2008. If you have a different version, search for SP_DBCMPTLEVEL to find out which value you should use.
EXEC SP_DBCMPTLEVEL 'Northwind', 100
OK, now that you have that, you're ready to install tSQLt. Go ahead and get the .zip file from here and extract it somewhere you can find. First run SetClrEnabled.sql on Northwind, then run tSQLt.class.sql.

At this point, tSQLt is installed on Northwind and you should be good to go to write tests. I made a couple of small changes to my instance that I'll share here. We have many users on our environment and we started to see situations where people were renaming tables outside of transactions (we'll get to that, don't worry) and it was causing us some headaches. In order to find the offenders and coach them on what they should do differently I modified a few objects. You can run the below code to make these same changes.
IF OBJECT_ID('tSQLt.Private_RenamedObjectLog') IS NOT NULL
BEGIN
    DROP TABLE tSQLt.Private_RenamedObjectLog
END
GO

CREATE TABLE tSQLt.Private_RenamedObjectLog (
    ID INT IDENTITY(1, 1) CONSTRAINT pk__private_renamedobjectlog_id PRIMARY KEY CLUSTERED
    ,ObjectId INT NOT NULL
    ,OriginalName NVARCHAR (MAXNOT NULL
    ,[NewName] NVARCHAR (MAXNULL
    ,RenamedBy VARCHAR(1000) NULL
    ,RenamedOn DATETIME2
)
GO

IF OBJECT_ID('tSQLt.Private_MarkObjectBeforeRename'IS NOT NULL
BEGIN
    DROP PROCEDURE tSQLt.Private_MarkObjectBeforeRename
END
GO

---Build+
CREATE PROCEDURE tSQLt.Private_MarkObjectBeforeRename
(
     @SchemaName NVARCHAR(MAX)
    ,@OriginalName NVARCHAR(MAX)
    ,@NewName NVARCHAR(MAX) = NULL
)
AS
BEGIN

    INSERT INTO tSQLt.Private_RenamedObjectLog (ObjectId, OriginalName, [NewName], RenamedBy, RenamedOn)
    VALUES (OBJECT_ID(@SchemaName +'.' + @OriginalName), @OriginalName, @NewName, SYSTEM_USERGETDATE())

END
GO
In the next installment, we'll actually check out the framework a little more and write a very basic test.