C# – Unit test doesn’t finish and stops all other tests from running

Problem

You have a unit test that doesn’t finish, and it prevents other tests from running. There’s no indication that the test passed or failed. It just stops running. When you run all of the tests together, some tests might finish, but once this one bad test stops, it prevents other tests from running.

This may be a new test you added. Or you changed some code, and now an existing test won’t finish.

Your test results might look something like this:

Test Explorer results showing that one of the unit tests didn't finish

Or it might look like this:

Test Explorer shows test didn't finish, but is showing the results from the previous run

In my opinion, the second scenario is worse, because the test results from the previous test run are shown, which is misleading.

In both cases, the test didn’t finish. You can tell a test didn’t finish because the pass/fail icon has a white background, instead of green/red/blue.

Note: To be clear, this is different than the problem where none of the unit tests run.

Solution

The most likely cause of a test not finishing is a stack overflow exception crashing your test host process.

The first step is to check the Tests output window to see what’s crashing the test host process:

  1. View > Output
  2. Show output from: Tests
---------- Starting test run ----------
The active test run was aborted. Reason: Test host process crashed : Stack overflow.

========== Test run aborted: 0 Tests run in 21.1 sec (0 Passed, 0 Failed, 0 Skipped) ==========
Code language: plaintext (plaintext)

Stack overflows can happen when you have recursive logic that is either recursing infinitely, or is recursing too deep. I’ll show a few examples of scenarios that cause this problem. You’ll need to look into your recursive code and figure out the root cause in your specific scenario.

Example – Infinite recursion

In this example, I implemented recursive Fibonacci without a base case.

public static int Fibonacci(int n)
{
	//purposely left out the base case, so this 
	//recurses until it blows up 

	return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Code language: C# (cs)

This results in it infinitely recursing and crashing the process with a stack overflow exception.

To fix this problem, I added a base case:

public static int Fibonacci(int n)
{
	if (n < 2)
		return n;

	return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Code language: C# (cs)

Example – Recursive code caught in a cycle

This is technically the same as infinite recursion. Basically the code is recursing through a tree or graph and it’s caught in a cycle due to circular references. Once it’s caught in the cycle, it’s the same thing as infinite recursion. Eventually it’ll cause a stack overflow.

To show this, I implemented a Tree, Node, and TreePrinter class. The TreePrinter class recurses through the tree and appends the values of the nodes.

public class TreePrinter
{
	public static string AppendValues(Tree tree)
	{
		return AppendNodeValues(tree.Root);
	}
	public static string AppendNodeValues(Node node)
	{
		if (node == null)
			return "";

		return node.Value + AppendNodeValues(node.Left) + AppendNodeValues(node.Right);
	}
}
public class Node
{
	public Node Left { get; set; }
	public Node Right { get; set; }
	public string Value { get; set; }
}
public class Tree
{
	public Node Root { get; set; }
}
Code language: C# (cs)

In my test, I purposely created a cycle by linking the Left and Right nodes to each other. This means when the TreePrinter recurses through these nodes, it’ll be caught in a cycle and will end up causing a stack overflow.

[TestMethod()]
public void TreeTest()
{

	var left = new Node() { Value = "1" };
	var right = new Node() { Value = "2" };

	//oops, a cycle
	left.Right = right;
	right.Left = left;

	Tree tree = new Tree()
	{
		Root = new Node()
		{
			Left = left,
			Right = right,
			Value = "0"
		}
	};

	Assert.AreEqual("012", TreePrinter.AppendValues(tree));
}
Code language: C# (cs)

There are two solutions to this:

  • Detect cycles and handle appropriately (either exit the cycle or throw an exception if they aren’t allowed, depending on your scenario).
  • Remove the cycle.

In my simple example, I’m just going to remove the cycle from the Tree object being tested.

[TestMethod()]
public void TreeTest()
{

	var left = new Node() { Value = "1" };
	var right = new Node() { Value = "2" };

	Tree tree = new Tree()
	{
		Root = new Node()
		{
			Left = left,
			Right = right,
			Value = "0"
		}
	};

	Assert.AreEqual("012", TreePrinter.AppendValues(tree));
}
Code language: C# (cs)

Leave a Comment