Red-Green-Code

Deliberate practice techniques for software developers

  • Home
  • About
  • Contact
  • Project 462
  • CP FAQ
  • Newsletter

Time Tortoise: Using SystemWrapper for Unit Testing

By Duncan Smith Oct 21 0

System Wrapper

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

An ongoing challenge when writing unit tests is isolating the class under test from the classes that it depends on. When you’re the one writing the dependencies, you can write them in a way that is friendly to unit testing. But when the dependencies are part of the framework you’re using, you have less control over the design. For .NET programmers who value unit testing, there’s a library called SystemWrapper whose purpose is to make .NET Framework apps more testable.

SystemWrapper

The .NET Framework is missing some features related to unit testing. In particular, not every class implements an interface. A simple example of this is DateTime. As I have written a few times this year, it’s difficult to unit test code that depends on DateTime.Now, since the current time is always changing, and unit tests need fixed values that they can assert against.

The solution: write your code to depend on an IDateTime interface, rather than directly on DateTime. Unfortunately, the .NET Framework doesn’t offer an IDateTime interface. So I created one earlier this year, and that’s what I’ve been using for unit testing.

But DateTime is just one class. The .NET Framework has numerous classes with the same problem. That’s where SystemWrapper comes in. The maintainers of SystemWrapper keep an eye on changes to the Framework, and update their project to keep in sync with it. So if you need to test code that depends on a .NET class, you may be able to find the appropriate interface in SystemWrapper.

IDateTime

Here’s how SystemWrapper works for DateTime.

Consider a class called TimeChecker that accepts a date/time provider of type IDateTime, and exposes a public method called GetCurrentDateTime that return the current date/time according to that provider.

SystemWrapper offers the IDateTime interface, and a class called DateTimeWrap that implements that interface. Here’s how a unit test could use IDateTime and Moq to test TimeChecker:

var dateTime = new Mock<IDateTime>();
dateTime.Setup(d => d.Now).
    Returns(new DateTimeWrap(new DateTime(2017, 10, 21)));
var ct = new TimeChecker(dateTime.Object);
Assert.Equal(new DateTime(2017, 10, 21),
    ct.GetCurrentDateTime().DateTimeInstance);

Moq can create a mock object based on an interface. In this case, we create a date/time provider that always thinks it’s October 21, 2017. Then we can use that date to verify that GetCurrentDateTime works correctly.

When we need a real date/time provider, we can create a DateTimeWrap using its default constructor:

var ct = new TimeChecker(new DateTimeWrap());

Now ct.GetCurrentDateTime() will return an IDateTime containing the system clock time.

IFileInfo

For my recent Daily Summary File work, I used code like this in a method called DailySummary.WriteFile:

var fileInfo = new FileInfo(fullName);
fileInfo.Directory.Create();

This isn’t ideal for unit testing, since it creates a real directory on the real disk. Unit tests shouldn’t write to disk, since that slows them down and leaves artifacts (files and directories on disk) when the tests are complete.

To avoid this, WriteFile should depend on an IFileInfo interface rather than the concrete FileInfo class. But System.IO.FileInfo doesn’t implement an interface. Fortunately, SystemWrapper has an IFileInfo interface and a FileInfoWrap class that implements it using System.IO.FileInfo.

As I was preparing to update my DailySummary class, I ran into a problem: SystemWrapper uses .NET Framework 4.5. But Time Tortoise (as of last week) is based on .NET Standard 1.4, so it can’t reference a net45 assembly.

I thought about trying to create a .NET Standard version of SystemWrapper, but quickly found out what a large project that would be. For example, when I added IFileInfo.cs to a .NET Standard class library project, I immediately got errors about the System.Security.AccessControl and SystemInterface.Security.AccessControl namespaces, which don’t exist in .NET Standard (even in v2.0).

As APIs continue to be added to .NET Standard, a time may come when the differences between .NET Standard and .NET Classic are small enough that SystemWrapper can be converted with minimal effort. But for now, SystemWrapper will have to serve merely as a source of code examples, rather than as a library I can directly reference from Time Tortoise.

(Image credit: Nate Grigg)

Categories: TT

Prev
Next

Stay in the Know

I'm trying out the latest learning techniques on software development concepts, and writing about what works best. Sound interesting? Subscribe to my free newsletter to keep up to date. Learn More
Unsubscribing is easy, and I'll keep your email address private.

Getting Started

Are you new here? Check out my review posts for a tour of the archives:

  • 2023 in Review: 50 LeetCode Tips
  • 2022 in Review: Content Bots
  • 2021 in Review: Thoughts on Solving Programming Puzzles
  • Lessons from the 2020 LeetCode Monthly Challenges
  • 2019 in Review
  • Competitive Programming Frequently Asked Questions: 2018 In Review
  • What I Learned Working On Time Tortoise in 2017
  • 2016 in Review
  • 2015 in Review
  • 2015 Summer Review

Archives

Recent Posts

  • Do Coding Bots Mean the End of Coding Interviews? December 31, 2024
  • Another Project for 2024 May 8, 2024
  • Dynamic Programming Wrap-Up May 1, 2024
  • LeetCode 91: Decode Ways April 24, 2024
  • LeetCode 70: Climbing Stairs April 17, 2024
  • LeetCode 221: Maximal Square April 10, 2024
  • Using Dynamic Programming for Maximum Product Subarray April 3, 2024
  • LeetCode 62: Unique Paths March 27, 2024
  • LeetCode 416: Partition Equal Subset Sum March 20, 2024
  • LeetCode 1143: Longest Common Subsequence March 13, 2024
Red-Green-Code
  • Home
  • About
  • Contact
  • Project 462
  • CP FAQ
  • Newsletter
Copyright © 2025 Duncan Smith