C# – Use StringAssert when testing a string for substrings

When you’re testing if two strings are equal, you can simply use Assert.AreEqual().

When you’re testing if a string contains a substring or a pattern, typically developers use Assert.IsTrue() with a substring method or regex. You should use StringAssert instead, because it gives better failure messages.

var greeting = "Hi Socrates, why are you here?";

//use this
StringAssert.Contains(greeting, "Hello");
/*
 * Failure message:
 * StringAssert.Contains failed. String 'Hi Socrates, why are you here?' does not contain string 'Hello'. .
*/

//instead of this
Assert.IsTrue(greeting.Contains("Hello"));
/*
 * Failure message:
 * Assert.IsTrue failed. 
 */ 
Code language: C# (cs)

Note: StringAssert is nice because it’s a built-in class. If you want to take it one step further and improve all of your unit tests, consider using FluentAssertions.

The key problem is Assert.IsTrue() gives useless information. You have to go look at the unit test to understand what it’s testing and why it failed. StringAssert solves the problem – it gives very helpful information.

In this article, I’ll show a full example comparing StringAssert vs Assert.IsTrue, and then show examples of how to use each of the StringAssert methods.

Example – Comparing StringAssert.Contains() with Assert.IsTrue()

Let’s say you have a mapper class. Given a person object, it outputs messages like this:

1234
2560a3e3cea7479ab28a4b56b0a4fc9f
<<full name based on culture rules>>
2021-01-04T08:15:42.0467508-05:00Code language: plaintext (plaintext)

Now you want to add a test that verifies it formats the person’s name according to the culture rules. How would you test this?

Here’s how you’d do it using Assert.IsTrue() with string.Contains():

[TestMethod()]
public void TestMapper_WhenNameIsBobSmith_AndRuleIsFamilyThenGiven_ThenMessageContainsSmithBob()
{
	//arrange
	var person = new Person()
	{
		FamilyName = "Smith",
		GivenName = "Bob",
		FullNameCultureRule = FullNameCultureRules.FamilyThenGiven
	};

	var mapper = new PersonMessageMapper();

	//act
	var message = mapper.MapToMessage(person);

	//assert
	Assert.IsTrue(message.Contains("Smith Bob"));
}
Code language: C# (cs)

The functionality isn’t implemented yet, so you expect the test to fail (test-first development). This test produces the following failure message:

Assert.IsTrue failed. Code language: plaintext (plaintext)

This doesn’t give any useful information about what was being tested or why it failed. To get more useful information, you can use StringAssert.Contains(), like this:

[TestMethod()]
public void TestMapper_WhenNameIsBobSmith_AndRuleIsFamilyThenGiven_ThenMessageContainsSmithBob()
{
	//arrange
	var person = new Person()
	{
		FamilyName = "Smith",
		GivenName = "Bob",
		FullNameCultureRule = FullNameCultureRules.FamilyThenGiven
	};

	var mapper = new PersonMessageMapper();

	//act
	var message = mapper.MapToMessage(person);

	//assert
	StringAssert.Contains(message, "Smith Bob");
}
Code language: C# (cs)

When this test fails, it produces the following failure message:

StringAssert.Contains failed. String '1234
7b4563cffaf243b9b00337b994e23c5d
2021-01-04T08:23:52.8571802-05:00
' does not contain string 'Smith Bob'. .Code language: plaintext (plaintext)

This failure message gives you enough information to understand why the test failed. You don’t even need to go look at the unit test to understand what it’s testing and why it failed. This is the mark of a good failure message.

Compare this with the bad failure message given by Assert.IsTrue() – which requires you to go look at the test to understand what it’s testing and why it failed.

StringAssert method reference

This section shows all of the StringAssert methods and examples of using them.

StringAssert.Contains()

Checks the string for a substring.

Example:

var message = "My name is Smith Bob";

StringAssert.Contains(message, "Smith Bob");
Code language: C# (cs)

StringAssert.StartsWith()

Checks the start of the string for a substring.

Example:

var message = "1234 Hello";

StringAssert.StartsWith(message, "1234");
Code language: C# (cs)

StringAssert.EndsWith()

Checks the end of the string for a substring.

Example:

var sb = new StringBuilder();
sb.AppendLine("1234");
sb.AppendLine("00");
var message = sb.ToString();

StringAssert.EndsWith(message, $"00{Environment.NewLine}");
Code language: C# (cs)

Note: This one can be tricky due to line endings.

StringAssert.Matches()

Checks if the string matches a regex pattern.

Example:

var message = Guid.NewGuid().ToString("N");

StringAssert.Matches(message, new Regex("[a-z0-9]{32}"));
Code language: C# (cs)

Note: DoesNotMatch() is the opposite.

Case insensitive matching

Unfortunately StringAssert.Contains() doesn’t have a way to do a case-insensitive string comparison.

Instead, you can use StringAssert.Matches() with RegexOptions.IgnoreCase like this:

var greeting = "Hello world";

StringAssert.Matches(greeting, new Regex("hello", RegexOptions.IgnoreCase));
Code language: C# (cs)