Assertions & Attributes
This page covers CustomAssert and the environment-aware test attributes.
CustomAssert⌗
CustomAssert is a static class with the null/empty assertions that come up most often, so you don’t have to
spell out Assert.True(collection is null || !collection.Any()) every time. Each method throws the same
exception type as a failing Assert, so failures read exactly like normal xUnit failures.
| Method | Passes when |
|---|---|
NullOrEmpty(IEnumerable?) | The collection is null or has no elements |
NotNullOrEmpty(IEnumerable?) | The collection is not null and has at least one element |
NullOrEmpty(string?) | The string is null or empty |
NotNullOrEmpty(string?) | The string is not null and not empty |
NullOrWhiteSpace(string?) | The string is null, empty, or only white space |
NotNullOrWhiteSpace(string?) | The string has at least one non-white-space character |
CustomAssert.NullOrEmpty(Array.Empty<int>()); // passes
CustomAssert.NullOrEmpty((IEnumerable?)null); // passes
CustomAssert.NotNullOrEmpty(new[] { 1, 2, 3 }); // passes
CustomAssert.NullOrWhiteSpace(" "); // passes
CustomAssert.NotNullOrWhiteSpace("value"); // passes
The collection overloads treat null and empty the same way, so a null reference never trips up a
NullOrEmpty check.
Environment-aware attributes⌗
Four attributes wrap xUnit’s [Fact] and [Theory] so a test can be skipped based on the active
environment or an explicit condition:
| Attribute | Wraps | Intended use |
|---|---|---|
UnitFactAttribute | [Fact] | Unit test |
UnitTheoryAttribute | [Theory] | Data-driven unit test |
FunctionalFactAttribute | [Fact] | Functional / integration test |
FunctionalTheoryAttribute | [Theory] | Data-driven functional test |
All four share the same two optional parameters:
UnitFact(EnvironmentType[]? environments = null, bool skipCondition = false)
environments— the environments in which the test must not run. The current environment is read from theASPNETCORE_ENVIRONMENTvariable and compared case-insensitively. When it matches one of the listed environments, the test is skipped with the reasonTest can't run on {environment}.null(the default) imposes no environment restriction.skipCondition— whentrue, the test is skipped regardless of the environment, with the reasonCondition to skip matched.
// Runs everywhere except Production.
[UnitFact([EnvironmentType.Production])]
public void Calculates_totals() { /* ... */ }
// Never runs while the feature flag is off, on any environment.
[FunctionalFact(skipCondition: FeatureFlags.PaymentsDisabled)]
public void Charges_card() { /* ... */ }
// Data-driven test blocked on Staging and Production.
[UnitTheory([EnvironmentType.Staging, EnvironmentType.Production])]
[InlineData(1)]
[InlineData(2)]
public void Validates_input(int value) { /* ... */ }
EnvironmentType comes from ArturRios.Configuration.Enums and defines Local, Development, Staging
and Production.
How the skip decision is made⌗
- If
skipConditionistrue, the test is skipped. - Otherwise, if
environmentsisnullor empty, the test runs. - Otherwise, the test is skipped when the current
ASPNETCORE_ENVIRONMENTmatches one of the listed environments.