Testing

44.1 Test Pyramid

Many unit tests (fast, isolated) → fewer integration tests (DB, HTTP, file system) → few end-to-end/UI tests.

44.2 Unit Tests (xUnit Example)

Frameworks: xUnit, MSTest (<TestMethod>, <DataRow>), NUnit (<Test>, <TestCase>). Mocking: Moq, NSubstitute, FakeItEasy. Assertions: FluentAssertions / Shouldly.

Testing time and randomness: inject TimeProvider (.NET 8) and FakeTimeProvider.

Imports Xunit
Imports Moq
Imports FluentAssertions

Public Class DiscountCalculatorTests
    <Fact>
    Public Sub Calculate_SumsApplicableRules()
        ' Arrange
        Dim rule1 As New Mock(Of IDiscountRule)
        rule1.Setup(Function(r) r.Applies(It.IsAny(Of Order)())).Returns(True)
        rule1.Setup(Function(r) r.Discount(It.IsAny(Of Order)())).Returns(10D)
        Dim rule2 As New Mock(Of IDiscountRule)
        rule2.Setup(Function(r) r.Applies(It.IsAny(Of Order)())).Returns(False)
        Dim sut As New DiscountCalculator({rule1.Object, rule2.Object})

        ' Act
        Dim result = sut.Calculate(New Order())

        ' Assert
        result.Should().Be(10D)
        rule2.Verify(Function(r) r.Discount(It.IsAny(Of Order)()), Times.Never())
    End Sub

    <Theory>
    <InlineData("", False)>
    <InlineData("a@b.com", True)>
    Public Sub EmailValidation(input As String, expected As Boolean)
        EmailValidator.IsValid(input).Should().Be(expected)
    End Sub
End Class

44.3 Integration and UI Tests

Testcontainers (real SQL Server/PostgreSQL in Docker), the SQLite in-memory provider for EF, Respawn for database resets, WebApplicationFactory for API tests, WireMock.Net for HTTP stubs.

UI automation: FlaUI / WinAppDriver (WinForms/WPF), Appium. Snapshot/approval testing: Verify.

Coverage: coverlet + ReportGenerator. Mutation testing: Stryker.NET (C#-focused, limited VB support).

44.4 TDD Workflow

Red → Green → Refactor. Write tests for bugs before fixing them. Keep tests deterministic and independent.