I’ve spent many hours during my career writing unit tests for classes that use data tables in .NET applications. In the past, I always felt that there was too much overhead in setting up a data table just so I could use it to verify my test case.
However, one day, I was writing one of these unit tests that involved significant setup code to construct a data table with about 20 columns and a single row. While doing so, it occurred to me that there might be a better way. So, after I finished the test case, I went back and tried to refactor the code to a more elegant solution.
I ended up applying the Builder design pattern to the construction of the test data table. In doing so, I dramatically simplified the setup code for the data table. This idea worked so well, in fact, that I went back and replaced all of the previous data table set-up code, with the new pattern, in about 40 other unit tests. Ever since that day, I have been using this new pattern when I need to create data tables in my unit test code.
As an example, here is the code that I would have written in the past to construct a data table for a single unit test:
var table = new DataTable(); table.Columns.Add("ID", typeof(int)); table.Columns.Add("Name", typeof(string)); table.Columns.Add("DOB", typeof(DateTime)); table.Columns.Add("Amount", typeof(double)); table.Columns.Add("Flag", typeof(bool)); var row = table.NewRow(); row.SetField("ID", 1); row.SetField("Name", "Matthew"); row.SetField("DOB", new DateTime(1978, 8, 2)); row.SetField("Amount", 1.23d); row.SetField("Flag", true); table.Rows.Add(row);
And here is the same code using the data table builder:
var table = new DataTableBuilder() .WithColumn("ID", 1) .WithColumn("Name", "Matthew") .WithColumn("DOB", new DateTime(1978, 8, 2)) .WithColumn("Amount", 1.23d) .WithColumn("Flag", true) .Build();
In addition, if I need to create a data table without any rows, I can easily do that as well:
var table = new DataTableBuilder() .WithColumn<int>("ID") .WithColumn<string>("Name") .WithColumn<DateTime>("DOB") .WithColumn<double>("Amount") .WithColumn<bool>("Flag") .Build();
Plus, if I need to write a test case that involves multiple rows in the data table, which I rarely ever do, this is relatively easy to do as well.
var table = new DataTableBuilder() .WithColumn<int>("ID") .WithColumn<string>("Name") .WithColumn<DateTime>("DOB") .WithColumn<double>("Amount") .WithColumn<bool>("Flag") .WithRow(1, "Matthew", new DateTime(1978, 8, 2), 1.23d, true) .WithRow(2, "Renze", new DateTime(2001, 2, 3), 2.34d, false) .Build();
As you can see, the data table builder reduces the number of lines of code by about half in the one-row test case. In addition, the new pattern is significantly easier to read. Plus, it makes the code much easier to reason about.
If you’d like to give this pattern a try in your own applications, I’ve published all of the source code in GitHub at the following repository URL: https://github.com/matthewrenze/data-table-builder
If you have any questions, comments, or feedback, please let me know.
In addition, if you like the way this pattern simplifies your unit test code, be sure to share the idea with your peers as well.