Fortunately, there's a really easy way to (unit) test html helpers for valid markup. For this, we'll use HtmlAgilityPack, "an HTML parser written in C#".
In the following example, I assume that you don't rely on the HtmlHelper
instance in your helper method. The assertion itself is done using Fluent Assertions, a really nice library for writing more readable test cases/assertions.
var replacedHtmlString = ((HtmlHelper) null).ReplaceToggleToken(SampleText, trackingKey);
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(replacedHtmlString.ToString());
htmlDocument.ParseErrors.Count().Should().Be(0);
Even though this code is straight forward and rather short, there will be a lot of repetition when testing multiple html helpers or testing multiple cases of the same helper. To overcome this, we can introduce a custom Fluent Assertions extension.
Such an extension consists of the assertions class:
public class HtmlStringAssertions : ReferenceTypeAssertions<HtmlString, HtmlStringAssertions> {
public HtmlStringAssertions(HtmlString instance) {
Subject = instance;
}
protected override string Identifier => "HtmlString";
public AndConstraint<HtmlStringAssertions> BeValidHtml(string because = "", params object[] becauseArgs) {
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => {
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(Subject.ToString());
return htmlDocument;
})
.ForCondition(htmlDocument => !htmlDocument.ParseErrors.Any())
.FailWith("Expected {context:HtmlString} to contain valid HTML{reason}.");
return new AndConstraint<HtmlStringAssertions>(this);
}
}
And the extension class:
public static class HtmlStringExtensions {
public static HtmlStringAssertions Should(this HtmlString instance) {
return new HtmlStringAssertions(instance);
}
}
Now, all that's left to do is to adjust the test case:
var replacedHtmlString = ((HtmlHelper)null).ReplaceToggleToken(SampleText, trackingKey);
replacedHtmlString.Should().BeValidHtml();
And now, happy testing :)