diff --git a/TUnit.Assertions.SourceGenerator/Generators/AssertionMethodGenerator.cs b/TUnit.Assertions.SourceGenerator/Generators/AssertionMethodGenerator.cs
index d2c023ea00..1120d2c753 100644
--- a/TUnit.Assertions.SourceGenerator/Generators/AssertionMethodGenerator.cs
+++ b/TUnit.Assertions.SourceGenerator/Generators/AssertionMethodGenerator.cs
@@ -699,7 +699,28 @@ private static void GenerateAssertConditionClassForMethod(SourceProductionContex
sourceBuilder.AppendLine();
}
- if (!attributeData.TargetType.IsValueType)
+ // Check if the method's first parameter accepts null values
+ // For static methods like string.IsNullOrEmpty(string? value), the first parameter
+ // is the value being asserted. If it's marked as nullable (NullableAnnotation.Annotated),
+ // we should skip the null check and let the method handle null values.
+ var shouldGenerateNullCheck = !attributeData.TargetType.IsValueType;
+ if (shouldGenerateNullCheck && staticMethod.Parameters.Length > 0)
+ {
+ var firstParameter = staticMethod.Parameters[0];
+ // Skip null check if the parameter explicitly accepts null (e.g., string? value)
+ if (firstParameter.NullableAnnotation == NullableAnnotation.Annotated)
+ {
+ shouldGenerateNullCheck = false;
+ }
+ // For backwards compatibility with .NET Framework where NullableAnnotation might not be set,
+ // also check for well-known methods that accept null by design
+ else if (methodName == "IsNullOrEmpty" || methodName == "IsNullOrWhiteSpace")
+ {
+ shouldGenerateNullCheck = false;
+ }
+ }
+
+ if (shouldGenerateNullCheck)
{
sourceBuilder.AppendLine(" if (actualValue is null)");
sourceBuilder.AppendLine(" {");
diff --git a/TUnit.Assertions.Tests/StringNullabilityAssertionTests.cs b/TUnit.Assertions.Tests/StringNullabilityAssertionTests.cs
new file mode 100644
index 0000000000..45c7b48969
--- /dev/null
+++ b/TUnit.Assertions.Tests/StringNullabilityAssertionTests.cs
@@ -0,0 +1,91 @@
+using TUnit.Assertions.Extensions;
+
+namespace TUnit.Assertions.Tests;
+
+///
+/// Tests for string assertions that accept null values (IsNullOrEmpty, IsNullOrWhiteSpace)
+///
+public class StringNullabilityAssertionTests
+{
+ [Test]
+ public async Task IsNullOrEmpty_WithNullString_Passes()
+ {
+ string? nullString = null;
+ await Assert.That(nullString).IsNullOrEmpty();
+ }
+
+ [Test]
+ public async Task IsNullOrEmpty_WithEmptyString_Passes()
+ {
+ var emptyString = "";
+ await Assert.That(emptyString).IsNullOrEmpty();
+ }
+
+ [Test]
+ public async Task IsNullOrEmpty_WithNonEmptyString_Fails()
+ {
+ var value = "Hello";
+ await Assert.That(async () => await Assert.That(value).IsNullOrEmpty())
+ .Throws();
+ }
+
+ [Test]
+ public async Task IsNullOrEmpty_WithWhitespace_Fails()
+ {
+ var value = " ";
+ await Assert.That(async () => await Assert.That(value).IsNullOrEmpty())
+ .Throws();
+ }
+
+ [Test]
+ public async Task IsNullOrWhiteSpace_WithNullString_Passes()
+ {
+ string? nullString = null;
+ await Assert.That(nullString).IsNullOrWhiteSpace();
+ }
+
+ [Test]
+ public async Task IsNullOrWhiteSpace_WithEmptyString_Passes()
+ {
+ var emptyString = "";
+ await Assert.That(emptyString).IsNullOrWhiteSpace();
+ }
+
+ [Test]
+ public async Task IsNullOrWhiteSpace_WithWhitespace_Passes()
+ {
+ var whitespace = " ";
+ await Assert.That(whitespace).IsNullOrWhiteSpace();
+ }
+
+ [Test]
+ public async Task IsNullOrWhiteSpace_WithNonEmptyString_Fails()
+ {
+ var value = "Hello";
+ await Assert.That(async () => await Assert.That(value).IsNullOrWhiteSpace())
+ .Throws();
+ }
+
+ [Test]
+ public async Task IsNotNullOrEmpty_WithNullString_Fails()
+ {
+ string? nullString = null;
+ await Assert.That(async () => await Assert.That(nullString).IsNotNullOrEmpty())
+ .Throws();
+ }
+
+ [Test]
+ public async Task IsNotNullOrEmpty_WithEmptyString_Fails()
+ {
+ var emptyString = "";
+ await Assert.That(async () => await Assert.That(emptyString).IsNotNullOrEmpty())
+ .Throws();
+ }
+
+ [Test]
+ public async Task IsNotNullOrEmpty_WithNonEmptyString_Passes()
+ {
+ var value = "Hello";
+ await Assert.That(value).IsNotNullOrEmpty();
+ }
+}