== Why is this an issue?

The rule targets test methods that lack an assertion and consist solely of an action and, optionally, a setup.

[source,csharp]
----
[TestMethod]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
}
----

Such tests only verify that the system under test does not throw any exceptions without providing any guarantees regarding the code's behavior under test.
Those tests increase the coverage without enforcing anything on the covered code, resulting in a false sense of security.

The rule identifies a potential issue when no assertions are present in tests utilizing the following frameworks:

* `MSTest`
* `NUnit`
* `xUnit`
* `FluentAssertions` (4.x and 5.x)
* `NFluent`
* `NSubstitute`
* `Shoudly`

By enforcing the presence of assertions, this rule aims to enhance the reliability and comprehensiveness of tests by ensuring that they provide meaningful validation of the expected behavior.

=== Exceptions

Test methods that include a call to a custom assertion method will not raise any issues.

== How to fix it

To address this issue, you should include assertions to validate the expected behavior.
Choose an appropriate assertion method provided by your testing framework (such as MSTest, NUnit, xUnit) or select a suitable assertion library like FluentAssertions, NFluent, NSubstitute, or Shouldly.

In addition to using built-in assertion methods, you also have the option to create custom assertion methods. To do this, declare an attribute named `[AssertionMethodAttribute]` and apply it to the respective method. This allows you to encapsulate specific validation logic within your custom assertion methods without raising the issue.
Here's an example:

[source,csharp]
----
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class CustomTestExample
{
    [TestMethod]
    public void Add_SingleNumber_ReturnsSameNumber()
    {
        var stringCalculator = new StringCalculator();
        var actual = stringCalculator.Add("0");
        Validator.AssertCustomEquality(0, actual); // Compliant
    }
}

public static class Validator
{
    [AssertionMethod]
    public static void AssertCustomEquality(int expected, int actual)
    {
        // ...    
    }
}

public class AssertionMethodAttribute : Attribute { }
----

== Hot to fix it in MSTest

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
[TestMethod]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
}
----

==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
[TestMethod]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
    Assert.AreEqual(0, actual);
}
----

== Hot to fix it in NUnit

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=2,diff-type=noncompliant]
----
[Test]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
}
----

==== Compliant solution

[source,csharp,diff-id=2,diff-type=compliant]
----
[Test]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
    Assert.That(0, Is.EqualTo(actual));
}
----

== Hot to fix it in xUnit

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=3,diff-type=noncompliant]
----
[Fact]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
}
----

==== Compliant solution

[source,csharp,diff-id=3,diff-type=compliant]
----
[Fact]
public void Add_SingleNumber_ReturnsSameNumber()
{
    var stringCalculator = new StringCalculator();
    var actual = stringCalculator.Add("0");
    Assert.Equal(0, actual);
}
----

== Resources

=== Documentation

* https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest[Unit testing C# with MSTest]
* https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-nunit[Unit testing C# with NUnit]
* https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test[Unit testing C# with xUnit]

=== Articles & blog posts

* https://www.everydayunittesting.com/2017/03/unit-testing-anti-pattern-not-asserting.html[Unit Testing anti-pattern]

ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

include::../message.adoc[]

'''
== Comments And Links
(visible only on this page)

=== on 2 May 2019, 14:44:07 Andrei Epure wrote:
This is implemented in https://github.com/SonarSource/sonar-dotnet/blob/7.13.0.8313/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/TestMethodShouldContainAssertion.cs[TestMethodShouldContainAssertion ]

include::../comments-and-links.adoc[]

endif::env-github,rspecator-view[]
