Category: .NET

Making NUnit parameterized tests less verbose

If you are a heavy user of NUnit parameterized tests, especially ones driven by TestCaseSourceAttribute, you might sometimes wish for a less verbose test data definition. Consider the following (contrived) example:

private static readonly object[] _additionCases =
{
  new object[] { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 0, 13), new DateTime(2017, 06, 06, 21, 16, 27) },
  new object[] { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 0, 56), new DateTime(2017, 06, 06, 21, 17, 10) },
  new object[] { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 59, 56), new DateTime(2017, 06, 06, 22, 16, 10) }
};

[Test, TestCaseSource(nameof(_additionCases))]
public void Addition(DateTime source, TimeSpan difference, DateTime expected)
{
  Assert.That(source.Add(difference), Is.EqualTo(expected));
}

Clearly, repeated new object[] type declarations steal some line width and don’t make understanding of the test data any easier.

However, there is a solution. While NUnit documentation illustrates TestCaseSourceAttribute with array of arrays, it also informs that any IEnumerable will do. Therefore, we can create our own class for that, and also use a succinct initialization trick for collections implementing Add method:

public class TestCaseList: List<object[]>
{
  public new void Add(params object[] data)
  {
    base.Add(data);
  }
}

With a help of this small class, the original test can be written as follows:

private static readonly TestCaseList _additionCases = new TestCaseList
{
  { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 0, 13), new DateTime(2017, 06, 06, 21, 16, 27) },
  { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 0, 56), new DateTime(2017, 06, 06, 21, 17, 10) },
  { new DateTime(2017, 06, 06, 21, 16, 14), new TimeSpan(0, 59, 56), new DateTime(2017, 06, 06, 22, 16, 10) }
};

[Test, TestCaseSource(nameof(_additionCases))]
public void Addition(DateTime source, TimeSpan difference, DateTime expected)
{
  Assert.That(source.Add(difference), Is.EqualTo(expected));
}

That looks definitely better!

Advertisements

Slow ASP.NET MVC website startup in case of many view folders

Recently we’ve observed that it takes too long for our ASP.NET MVC web application to be up and running after a build. It didn’t take long to find out that the cause of the problem was the recompilation of Razor views.

Most of people on the Internet are concerned with the downtime of the production environments after rolling out a new version, and the pre-compilation of views is able to solve it. However, in our case it’s the development process that is being hampered, so naturally pre-compilation gains nothing. Other commonly found advices like turning off unused view engines haven’t had significant results as well.

But why does it take so long to compile a bunch of views? It turns out, the complexity of views affect the total time only to a small extent, but what really matters is how much view folders are there, specifically how much views located outside of the current folder a given view uses.

I’ve created a small application based on the default ASP.NET MVC project with several partials added to the Home page:

partialsproject

Let’s see what Mini Profiler can tell us about the rendering times of the Index page right after a build:

compilationtime

Results suggest that the first partial is so complex that it takes a lot of time to render it; however, the view consists only of a small text string, and swapping the content with other partials does not make any difference. Moreover, partials 2 and 3 take practically no time to render, and so does the partial located in the same folder as the view.

Further experimentation confirms that the rendering of a partial itself takes a negligible amount of time – however, the first time framework encounters a new folder, it stumbles quite noticeably , obviously performing some activity.

Why is it so? Let’s run the trusty DotTrace:

trace

Let’s look at CompileWebFile method in Microsoft reference sources:

https://referencesource.microsoft.com/#System.Web/Compilation/BuildManager.cs,1662

compiledir

So it seems that whenever the view compiler sees a web file, it tries to compile the whole directory (but not more!). What happens next is that we run the compiler and wait until it’s done:

http://www.symbolsource.org/…Compiler.cs

compile

Starting a process is an expensive task, of course, so that explains why we were observing a noticeable delay.

The conclusion to be made is that a dashboard style home pages doesn’t play well with ASP.NET MVC if their component views are located in different folders. I do not know a solution to this problem, because the build strategy is buried well inside the MVC internals, so for now the advice would be to keep everything you reference in the same folder as much as possible.

ccnet and git

CruiseControl.NET has a built-in git integration via Git Source Control Block. Still, when using msysgit on Windows connecting to a github repository, you may find out that ccnet will hang on getting the sources until timeout kills the build. For me the simplest solution that worked was to run ccnet service under the user account I used git before (I guess it has something to do with SSH keys). In a different situation you may want to create a dedicated account, setup the git, including keys and all, and then use this account for CruiseControl service.

ccnet statistics

If you want to display statistics on a web dashboard of CruiseControl.NET 1.5 or higher, don’t forget first to set non-empty password in administrationPlugin section of dashboard.config and reload IIS (simply restarting dashboard won’t help). After that you can open dashboard in a browser, enter the administration section and enable Project Statistics plugin from there (for some older systems full access to packages.xml maybe be required for user running ccnet), and then add projectStatisticsPlugin into the section of dashboard.config. After reloading the dashboard you’ll see the “View Statistics” link leading to some simple graphs and numbers.

First steps in NHibernate development. Mapping

I continue my NHibernate development posts. In the previous post I showed the necessary steps to set up the framework, but there was nothing really useful above that. Now it’s time to go further to mapping files.

Mapping files define the relationship between the domain model classes and database tables. The first question that comes to mind is where to start: you can design your database tables first and create classes after that, or start with domain model and then define the database. For most greenfield projects I would recommend to start prototyping your application with classes first, and then gradually pay more and more attention to the database issues (you’ll definitely need this at the deploy time and later on).

Let’s start with the following example: imagine you are developing an online game and need to persist some information into the database.  Take the project we’ve created in the previous post and add Player class with Name and Rating properties:

    class Player
    {
        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual int Rating { get; set; }
    }

Notice we need the unique identifier property in a class; some other options are possible but generally are more cumbersome to work with. Also, all the properties are marked with virtual keyword. I’ll discuss the reasons for this requirement in future posts when talking about proxies and lazy loading.

Now we want to tell NHibernate how to save Player objects into the database. Add XML file named Player.hbm.xml to the project. Write the following lines in this file:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  assembly="firstSteps" namespace="firstSteps">
  <class name="Player">
    <id name="Id">
      <generator class="native"/>
    </id>
    <property name="Name"/>
    <property name="Rating"/>
  </class>
</hibernate-mapping>

On the top of this XML there is a hibernate-mapping element, stating the assembly and the namespace to search your domain classes in. Inside you can see a class mapping. That’s the simplest mapping possible; it maps the class to the table with the same name (by default as no table name is specified), then maps every listed property to the column with the same name, and uses identifier generation strategy supplied by the underlying database server (identity field on SQL Server).

Add the following line before running Configure method of NHibernate configuration object:

config.AddFile("Player.hbm.xml");

Now we’ve created the mapping between the Player class and the corresponding table, but the database does not have any tables yet. Of course, you can go and create Player table with all the required columns, but there is a better solution. For the most part of development time you’ll want NHibernate to automatically generate database metadata from mapping files. It’s quite handy because NHibernate can even gently update the existing database when you add or modify your mapping.

Add the following line after the Configure() call:

var sessionFactory = config.BuildSessionFactory();

(parameters mean “do not process generated script further” and “do update the database”).

You can run the program and see that the table has really been created.

Finally, we can actually write some code to add a new player to the database:

var player = new Player { Name = "Killer Bean", Rating = 2200 };

using (var session = sessionFactory.OpenSession())
{
    session.Save(player);
}

Console.WriteLine("Added player #{0}", player.Id);

Run the program and see how it’s inserting new records: we’ve done it! But it’s enough for this time, we’ll discuss the basic data manipulation in the next post in the series.

P.S. Experienced database developer can ask “What if I already have the database and need to set up the tables and column names, nullable flags, column length etc.?“ In fact NHibernate has rich mapping capabilities to satisfy even the most demanding requirements. You can explore the NHibernate documentation at nhforge and load mapping XSD from Required_Bins NHibernate folder into the Visual Studio to put Intellisense to operation.

First steps in NHibernate development. Setting up

NHibernate is a highly customizable and tried open source ORM framework for the .NET platform. While it is a very powerful tool, it’s often being criticized due to the very steep learning curve. Indeed, its Java legacy results in a lot of XML configuration, and feature richness brings a large API to comprehend, making diving in NHibernate a hard step for a regular .NET developer. That’s why I will make the series of posts describing NHibernate development in hope to help the beginners.

I will use NHibernate 2.1.2 with Microsoft SQL Server Express 2005 in a console application project.

Let’s go!

  1. Download NHibernate from its sourceforge site, unpack files to some folder.
  2. Create a console application project. Add reference to NHibernate.dll from Required_Bins subfolder of the folder you’ve created on the previous step. Add reference to the NHibernate.ByteCode.LinFu.dll from Required_For_LazyLoading\LinFu folder.
  3. Create the application configuration file (app.config) and make it look like this:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="hibernate-configuration"
         type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
      </configSections>  
      <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
          <property name="dialect">
            NHibernate.Dialect.MsSql2005Dialect
          </property>     
          <property name="connection.connection_string">
            Server=.\SQLEXPRESS;initial catalog=NHFirstSteps;
            Integrated Security=SSPI
          </property>
          <property name="proxyfactory.factory_class">
            NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
            NHibernate.ByteCode.LinFu
          </property>
        </session-factory>
      </hibernate-configuration>
    </configuration>
    
  4. Create a database named NHFirstSteps in the SQL Express.
  5. Put NHibernate.Cfg namespace in the using section of the program. Add the following code to the Main method:
    var config = new Configuration();
    config.Configure();
    var sessionFactory = config.BuildSessionFactory();
    
    Console.WriteLine("Hello, NHibernate!");
    
  6. Now run the console app. If you are seeing the “Hello, NHibernate!” message, all the settings are correct and you are ready to go further.

But wait for a minute, what’s the meaning behind all these magical passes?

Of course, referencing NHibernate.dll is a natural way to use framework’s capabilities, but adding NHibernate.ByteCode.LinFu.dll is a little bit more interesting. That is required to support lazy loading feature, and in fact you can choose from the three implementations out there: Castle Dynamic Proxy, LinFu Dynamic Proxy or Spring AOP. Don’t be afraid – you don’t need to delve in these matters right now, just select one proxy library and set its name in the proxyfactory.factory_class property of the configuration file.

Another required setting in the configuration file is, of course, database server type (dialect) and actual database connection string. All the common database servers such as MS SQL, Oracle, DB2, MySQL, PostgreSQL are supported. Database connection string must be in the format specified by the ADO.NET driver being used (this example uses SQL Server connection string with local SQL Express server, NHFirstSteps database and Windows authentication).

In the code we initialize NHibernate (by default configuration is loaded from the application config file) and build session factory. Session factory is a tool to make sessions, the main objects in the NHibernate development. Sessions implement unit of work pattern and allow you to load, save and query the data.

Note that both configuration and session factory building are very time-consuming processes, and usually should be called once at the app domain start.

Where to go next? Wait for the next post in NHibernate first steps series!