Senior 5 min · March 06, 2026

Mocking with Moq: Missing Setup Returns Null in Production

Missing mock setup for a new method overload caused a NullReferenceException in production.

N
Naren Founder & Principal Engineer

20+ years shipping production .NET services in enterprise systems. Lessons pulled from things that broke in production.

Follow
Production
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Moq creates fake implementations of interfaces or abstract classes for isolated unit tests.
  • Setup defines expectations: mock.Setup(x => x.Method()).Returns(value).
  • Verification ensures methods were called with expected arguments and counts.
  • Callbacks execute code when a mocked method is invoked, useful for side effects.
  • Sequences model ordered calls with SetupSequence, perfect for state machines.
  • Production trap: Loose mocks silently return default values hiding missing setups.
✦ Definition~90s read
What is Mocking with Moq in C#?

Moq (pronounced 'mock-you') is a .NET library that generates proxy implementations of interfaces and abstract classes at runtime. When you call a method on the proxy, Moq intercepts it and returns the value you specified via Setup. This lets you replace real dependencies — a database context, an HTTP client, a file system — with a controllable fake. The two fundamental operations are:

Imagine you're testing a new recipe but you don't want to use real expensive ingredients every time — so you use plastic fruit that looks and behaves exactly like the real thing.

1. Setup — tell the mock how to behave when a method is called. 2. Verify — assert that the method was called with the expected arguments.

Moq supports two mock behaviors: - Loose (default) — returns default values for unmatched calls. Dangerous because missing setups hide failures. - Strict — throws an exception for any call without a Setup. Harder to maintain but safe.

Senior engineers almost always start with Strict in new tests and loosen only when there's a good reason, typically to reduce boilerplate for test utility methods.

Plain-English First

Imagine you're testing a new recipe but you don't want to use real expensive ingredients every time — so you use plastic fruit that looks and behaves exactly like the real thing. Moq is that plastic fruit for your C# code. It creates fake versions of your dependencies (databases, APIs, email services) that behave exactly how you tell them to, so you can test your logic in total isolation without touching anything real.

Every serious C# application talks to things it doesn't control — databases that can go offline, payment APIs that cost money per call, email servers that send real emails to real people. When you want to test the logic that orchestrates all those moving parts, you can't just fire up the real infrastructure for every test run. That's not just slow — it's unpredictable, expensive, and a maintenance nightmare. This is the problem unit testing was born to solve, and it's the reason mocking frameworks exist. Moq is the most popular mocking library in .NET. It's mature, flexible, and it handles the vast majority of what you'll need. But it's not magic. Without understanding its internals — how Setup, Returns, Verify, Callback, and SetupSequence actually work — you'll write tests that pass in isolation but fail in production. This guide goes deep into those mechanics and the patterns that separate senior engineers from the rest.

What Is Mocking with Moq in C#?

Moq (pronounced 'mock-you') is a .NET library that generates proxy implementations of interfaces and abstract classes at runtime. When you call a method on the proxy, Moq intercepts it and returns the value you specified via Setup. This lets you replace real dependencies — a database context, an HTTP client, a file system — with a controllable fake. The two fundamental operations are:

  1. Setup — tell the mock how to behave when a method is called.
  2. Verify — assert that the method was called with the expected arguments.
Moq supports two mock behaviors
  • Loose (default) — returns default values for unmatched calls. Dangerous because missing setups hide failures.
  • Strict — throws an exception for any call without a Setup. Harder to maintain but safe.

Senior engineers almost always start with Strict in new tests and loosen only when there's a good reason, typically to reduce boilerplate for test utility methods.

TheCodeForge/MoqDemo/BasicMock.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace TheCodeForge.MoqDemo;

public interface IEmailService
{
    void Send(string to, string subject, string body);
}

// Test example
[Fact]
public void Send_email_calls_service()
{
    var mock = new Mock<IEmailService>(MockBehavior.Strict);
    mock.Setup(m => m.Send("user@example.com", "Hi", It.IsAny<string>()));

    var service = new NotificationService(mock.Object);
    service.SendWelcomeEmail("user@example.com");

    mock.Verify(m => m.Send("user@example.com", "Hi", It.IsAny<string>()), Times.Once);
}
Output
Test passes — proves Send was called exactly once with expected arguments.
Production Insight
Strict mode catches missing setups at test time, not in production.
Loose mode hides bugs until NullReferenceException appears in logs.
Rule: default to Strict, relax only when absolutely necessary.
Key Takeaway
Moq intercepts virtual method calls on generated proxies.
Setup defines behavior; Verify asserts invocation.
Strict is safe; Loose is fast — know the trade-off.
Moq Mocking Workflow and Production Pitfalls THECODEFORGE.IO Moq Mocking Workflow and Production Pitfalls From setup to verification with common gotchas in async and partial mocks Setup Mocks with Returns/Throws Use .Returns() and .Throws() for method behavior Verify Method Calls Ensure expected invocations with .Verify() Advanced Patterns: Callbacks & Sequences Use .Callback() and .SetupSequence() for complex flows Production Gotchas: MockBehavior & Async Strict vs Loose; async timeouts and Task pitfalls Partial Mocks: Real Object with Mocked Parts Use .CallBase() for real implementation on selected methods Mock Internals and Protected Members Use .Protected() and InternalsVisibleTo for testing ⚠ Missing setup returns null in production with Loose mock Use Strict MockBehavior or always provide .Returns() for expected calls THECODEFORGE.IO
thecodeforge.io
Moq Mocking Workflow and Production Pitfalls
Mocking Moq Csharp

Setting Up Mocks — Returns, Throws, and Parameters

Setup is the core operation. You express: 'When method X is called with arguments matching these conditions, do Y.' The matching engine supports exact values, predicate expressions, and wildcard matchers like It.IsAny<T>(), It.Is<T>(predicate), and It.IsInRange<T>(min, max).

Returns() specifies the return value or an expression that computes it lazily. Throws() makes the mock throw an exception. For void methods, you call .Callback to execute side effects, though Returns is not applicable.

Parameters can be matched by value, condition, or any. Be careful with reference types — Moq uses Equals() for matching, so custom objects need proper Equals override or use It.Is<T>(x => x.SomeProperty == expected).

TheCodeForge/MoqDemo/SetupExamples.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace TheCodeForge.MoqDemo;

public interface IOrderRepository
{
    Order GetById(int id);
    void Save(Order order);
}

// Test: setup with predicate and Returns
[Fact]
public void GetById_returns_specific_order()
{
    var mock = new Mock<IOrderRepository>(MockBehavior.Strict);
    mock.Setup(r => r.GetById(It.Is<int>(id => id > 0)))
        .Returns<int>(id => new Order { Id = id, Amount = 100 });

    var result = mock.Object.GetById(42);
    Assert.Equal(100, result.Amount);
}

// Setup throws
mock.Setup(r => r.Save(It.IsAny<Order>()))
    .Throws<DbConcurrencyException>();
Output
The GetById test passes only for IDs > 0; Save throws expected exception.
Production Insight
Using It.Is<T>() with a predicate can become slow if the predicate is expensive.
For hundreds of calls, prefer exact matching or a simple It.IsAny<T>() to avoid test slowdown.
Rule: keep predicates cheap and avoid database calls in predicates.
Key Takeaway
Setup matching is the heart of Moq.
Use It.Is for flexible matching, exact values for precision.
Lazy Returns with expressions keep tests DRY.

Verification — Ensuring Methods Were Called

Verification is the second pillar. After the SUT runs, you ask: 'Was method X called exactly N times with these arguments?' The Verify method takes the same expression as Setup, plus an optional Times constraint. Without the times parameter, it defaults to Times.AtLeastOnce().

Common pitfalls
  • Verifying a call that was _not_ set up will throw a MockException even if the code never calls it — because the default behavior for unmatched calls in Strict mode is to throw at call time, not verify time.
  • Verifying with It.IsAny<T>() but the actual argument is null — It.IsAny<T>() matches null when T is nullable, but not for value types (struct).
  • VerifyAll() vs Verify() — VerifyAll checks all setups, including those not explicitly verified. Use it sparingly to avoid brittle tests.
TheCodeForge/MoqDemo/VerificationExamples.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace TheCodeForge.MoqDemo;

[Fact]
public void Verify_multiple_invocations()
{
    var mock = new Mock<ILogger>(MockBehavior.Loose);
    var service = new Processor(mock.Object);
    
    service.RunBatch(new[] { 1, 2, 3 });
    
    // Verify exactly 3 calls to LogInfo
    mock.Verify(l => l.LogInfo(It.IsAny<string>()), Times.Exactly(3));
    // Verify LogError was never called
    mock.Verify(l => l.LogError(It.IsAny<string>()), Times.Never);
}
Output
Test passes because RunBatch logged three times and no errors.
Production Insight
Over-verification leads to brittle tests — changing implementation details breaks tests.
Only verify calls that are part of the contract, not internal side effects.
Rule: verify the 'what', not the 'how' — prefer state-based assertions when possible.
Key Takeaway
Verify checks method call counts and arguments.
Times.Once, Times.Exactly, Times.Never are your tools.
Don't verify implementation details — test behavior, not calls.

Advanced Patterns — Callbacks, Sequences, and Recursive Mocks

Callbacks allow you to inspect or modify the arguments passed to the mocked method. Use .Callback<T1, T2>(...) with matching argument types to capture values. This is invaluable for testing code that pushes data into a dependency — you can assert what was sent.

Sequences model multi-step interactions where the same method must return different values on successive calls. SetupSequence() accepts a chain of Returns, Throws, or Callbacks. After the last item, subsequent calls throw by default (unless you add a final Returns for covering).

Recursive mocks happen when a mock returns another mock. If your interface returns an interface, and that interface returns another, you can set up the chain automatically using DefaultValue.Mock. This reduces boilerplate but can hide deep failures.

TheCodeForge/MoqDemo/AdvancedPatterns.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace TheCodeForge.MoqDemo;

public interface IStateMachine
{
    State GetNext();
}

[Fact]
public void Sequence_returns_in_order()
{
    var mock = new Mock<IStateMachine>(MockBehavior.Strict);
    mock.SetupSequence(m => m.GetNext())
        .Returns(State.Initial)
        .Returns(State.Processing)
        .Returns(State.Final);

    Assert.Equal(State.Initial, mock.Object.GetNext());
    Assert.Equal(State.Processing, mock.Object.GetNext());
    Assert.Equal(State.Final, mock.Object.GetNext());
}

//Callback to capture argument
var callbackArg = string.Empty;
mock.Setup(x => x.Log(It.IsAny<string>()))
    .Callback<string>(msg => callbackArg = msg);
Output
Sequence test verifies ordered state transitions; callback captures the log argument.
Production Insight
Sequences are powerful but brittle across concurrent tests — each call modifies shared state.
Callback closures can cause subtle bugs if the captured variable is reused across tests.
Rule: reset captured state in test setup (collection fixture) or use local variables per test.
Key Takeaway
Callbacks capture arguments for later assertions.
SetupSequence models ordered interactions.
Recursive mocks reduce boilerplate but increase test complexity.

Production Gotchas — MockBehavior, Async, and Timeouts

Even with solid test coverage, Moq can betray you in production. The most common incidents:

  1. Loose behavior masking missing setups — your test passes because Moq returns null/0 for unset methods, but production code expects a real object.
  2. Async mocks not awaited — a method returning Task but not awaited in the SUT means the mock's ReturnsAsync is never observed; the test may pass but production runs synchronously or deadlocks.
  3. Time-dependent mocks — mocking DateTime.Now or similar static calls is impossible with Moq; you need to inject an abstraction (e.g., ISystemClock).
  4. Out/ref parameters — hard to set up and verify. Use It.Ref<T>.IsAny for ref matching and store output values via Callback.

Senior engineers always run their test suite with both mock behaviors at least once during CI to catch Loose-vs-Strict discrepancies.

TheCodeForge/MoqDemo/ProductionGotchas.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace TheCodeForge.MoqDemo;

// Async setup
mock.Setup(x => x.GetDataAsync()).ReturnsAsync(new Data());

// SUT must await, else test may pass but production runs sync
// public async Task<Data> Fetch() => await _dependency.GetDataAsync();

// Ref parameter
mock.Setup(x => x.TryGetValue(It.IsAny<int>(), out It.Ref<int>.IsAny))
    .Callback(new InvocationAction(invocation =>
    {
        invocation.Arguments[1] = 42; // assign output
    }))
    .Returns(true);
Output
Async mock works only if awaited; ref parameters need special handling.
Production Insight
Switching from Loose to Strict can reveal 10-20 missing setups in an established codebase.
Address them by either adding the missing Setup (preferred) or switching individual methods to Loose.
Rule: keep a 'StrictMode' global switch in your test base class for troubleshooting.
Key Takeaway
Loose hides bugs; Strict reveals them.
Async mocks require proper awaiting in SUT.
Inject abstractions for time, random — don't mock statics.

Partial Mocks — When You Need a Real Object with a Few Fakes

You're testing a legacy payment service that makes a database call you can't untangle easily. You don't want to mock the entire thing — that's 14 interfaces and a prayer. You need one real method and one fake.

Partial mocks let you create a real instance of a class and override specific members. Moq does this with As() or by passing a mock to the constructor. The rule: default behavior is real, setup behavior overrides it.

Why reach for this? When you own the code and refactoring isn't on the table. When a third-party SDK has 50 virtual methods and you only need to intercept two. It's surgical.

Warning: partial mocks are a code smell. If you're doing this more than once a quarter, your design is broken. The real fix is an interface. But for today's hotfix at 2 AM, this is what saves your ass.

PartialPaymentService.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// io.thecodeforge — csharp tutorial

public class PaymentProcessor
{
    public virtual bool Authorize(string card)
    {
        return ExternalSdk.Call(card); // Real call
    }

    public virtual bool Refund(string transactionId)
    {
        throw new NotImplementedException(); // Legacy junk
    }
}

[Test]
public void Refund_Fails_Gracefully()
{
    var mock = new Mock<PaymentProcessor>();
    mock.Setup(p => p.Refund(It.IsAny<string>()))
        .Returns(false);

    // Authorize uses real implementation
    // Refund uses our fake
    var processor = mock.Object;
    var refunded = processor.Refund("txn_abc");

    Assert.That(refunded, Is.False);
}
Output
Test passes. Refund returns false.
Authorize still calls ExternalSdk (if invoked).
Legacy Trap:
Partial mocks require virtual methods. If your class doesn't have them, you can't mock. That's your hint to introduce an interface. Do it before the code rots further.
Key Takeaway
Partial mocks = real instance + selective overrides. Use only when refactoring is blocked.

Mocking Internals and Protected Members — Breaking the Barrier

You need to test an internal method that does the heavy lifting. Someone sealed the class. The method is protected virtual. Moq doesn't care about your access modifiers if you use Mock.Protected().

This is for white-box testing. You're asserting how the sausage is made, not just what comes out. You're doing it because the public interface is too coarse to isolate the bug.

Setup a protected member: mock.Protected().Setup<bool>("InternalCheck", ItExpr.IsAny<int>()).Returns(true). Verification works the same way. The string name must match exactly. No refactoring safety. No compiler errors if you rename it. That's the cost.

Senior shortcut: use this only when you control the source and the test proves a specific logic path. If you find yourself mocking internals of a third-party assembly, stop. You're doing integration testing in a unit test harness. That's a different tool.

ProtectedMockScenario.csCSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// io.thecodeforge — csharp tutorial

public class ReportEngine
{
    protected virtual bool ValidateReport(string reportId)
    {
        // Complex validation logic
        return reportId.StartsWith("RPT");
    }

    public string Generate(string reportId)
    {
        return ValidateReport(reportId) ? "OK" : "FAIL";
    }
}

[Test]
public void Generate_Returns_OK_When_Validation_Passes()
{
    var mock = new Mock<ReportEngine>();
    mock.Protected()
        .Setup<bool>("ValidateReport", ItExpr.IsAny<string>())
        .Returns(true);

    var result = mock.Object.Generate("RPT_001");

    Assert.That(result, Is.EqualTo("OK"));
}
Output
Test passes.
ReportEngine.Generate returns "OK".
Senior Shortcut:
Use nameof() for the method string when possible. It's not perfect for protected, but it catches typos at compile time. Example: mock.Protected().Setup<bool>(nameof(ValidateReport)...) — doesn't work for protected, so fall back to const string. Painful but safer.
Key Takeaway
Mock protected members with .Protected() when you must test internals. Accept the string-based fragility.
● Production incidentPOST-MORTEMseverity: high

The Silent ReturnNull — When Missing Mock Setup Breaks Production

Symptom
Unit tests pass, but in production the application crashes with NullReferenceException when calling a method on a dependency that was mock-setup for a different signature.
Assumption
The team assumed that because they had a mock for the service, all its methods were automatically handled — and that missing a Setup would cause an immediate test failure.
Root cause
Moq's Loose mock behavior (default) returns default(T) for any method that hasn't been explicitly set up. The team added a new overload of a method to the interface but forgot to add a corresponding mock Setup. The test exercised a different code path, so the missing Setup never surfaced.
Fix
Switch to Strict mock behavior during development (var mock = new Mock<IService>(MockBehavior.Strict)), which forces every method call to have a setup. Alternatively, run a test coverage analysis that maps unit test execution to mock setups.
Key lesson
  • Never assume all mock methods are covered unless you use Strict mode.
  • Add a test that explicitly exercises every branch that calls each mocked interface method.
  • Review mock setups when the interface changes — treat missing setups as production bugs.
Production debug guideSymptom → Action guide for the most common Moq gotchas5 entries
Symptom · 01
Mock returns null or default unexpectedly
Fix
Check if the mock's Setup matches the exact arguments passed at runtime. Use It.IsAny<T>() for flexible matching, and add a .Callback to log what's being passed.
Symptom · 02
Verify throws MockException: 'Expected invocation on the mock N times, but was never performed'
Fix
Confirm the code path under test actually reaches that method call. Use .Callback to trace. Also check if the mock is being passed to the right dependency instance.
Symptom · 03
Test passes but production code fails with NullReferenceException on the same code path
Fix
Your mock likely returns a null object when the real dependency returns something else. Use MockBehavior.Strict or add .Returns() for all overloads. Also consider using DefaultValue.Mock for recursive mocks.
Symptom · 04
Callback or Returns are not invoked
Fix
Verify that the method call matches the Setup exactly, including generic type parameters and ref/out parameters. Use Setup(x => x.Method(It.IsAny<int>(), ref It.Ref<int>.IsAny)).Callback(...) for ref parameters.
Symptom · 05
Async method mock returns Task but test hangs or fails with 'Cannot await Mock<T>'
Fix
For async methods, always use .ReturnsAsync(value) not .Returns(Task.FromResult(value)). Actually both work, but ReturnsAsync is cleaner. Ensure the async target method is actually awaited in the SUT.
★ Quick Debug Cheat Sheet — Moq in ProductionRapid-fire commands and fixes for the most common Moq debugging scenarios. No theory, just what to type and where to look.
Mock returns null unexpectedly
Immediate action
Check MockBehavior — default Loose allows null returns. Switch to Strict in test config.
Commands
var mock = new Mock<IService>(MockBehavior.Strict);
mock.SetupAllProperties(); // for property stubs
Fix now
Add Setup for that exact method signature, or use It.IsAny<T>() for flexible matching.
Verify fails: 'Expected invocation 1 times, but was 0'+
Immediate action
Add .Callback((args) => Console.WriteLine($"Called with {args}")); to the Setup to trace calls.
Commands
mock.Setup(x => x.Method(It.IsAny<int>())).Callback<int>(arg => Console.WriteLine(arg));
mock.Verify(x => x.Method(It.Is<int>(i => i > 0)), Times.Once);
Fix now
Use It.Is<> with a predicate if you only want to verify specific argument values.
Async mock not awaited properly — test passes but production blows up+
Immediate action
Verify the SUT actually awaits the mock method. A missing await means a Task is never completed.
Commands
// In SUT: await dependency.DoSomethingAsync()
// In test: mock.Setup(x => x.DoSomethingAsync()).ReturnsAsync(new Result());
Fix now
If the SUT doesn't await, the mock's ReturnsAsync may never be observed. Add a synchronous overload or ensure the caller awaits.
SetupSequence not producing expected values on later calls+
Immediate action
Check that the test calls the method exactly as many times as the sequence defines. Extra calls will throw if no default.
Commands
mock.SetupSequence(x => x.GetState()).Returns('A').Returns('B').Returns('C');
// Call three times — each returns next in sequence
Fix now
To handle variable number of calls, combine with Callback to track count and conditionally return values.
FeatureWhen to UseRisk if Overused
MockBehavior.LooseQuick prototyping, rarely used code pathsMissing setups hide production bugs
MockBehavior.StrictCritical interfaces, contract testsBrittle tests, high maintenance
SetupSequenceState machines, read-once streamsOrder-dependent tests fail unexpectedly
CallbackCapturing arguments, complex validationShared state across concurrent tests
DefaultValue.MockDeep dependency chains, no need to customize intermediate mocksDifficult to trace where the real return value came from

Key takeaways

1
Moq creates proxy implementations
Setup defines behavior, Verify asserts invocations.
2
Strict mode catches missing setups early; Loose mode hides them until production crashes.
3
Use Callback for side effects, SetupSequence for ordered returns, and DefaultValue.Mock for deep chains.
4
Async mocks require the SUT to actually await
otherwise the ReturnsAsync never fires.
5
Inject abstractions for time, random, and other static dependencies
Moq can't mock statics.
6
Run test suite under both Loose and Strict during CI to uncover discrepancies.

Common mistakes to avoid

3 patterns
×

Using Loose mock behavior as default and never switching

Symptom
Tests pass but production code crashes with NullReferenceException when a new method is called on a mock that hasn't been set up. The default returns null, masking the missing setup.
Fix
Use MockBehavior.Strict as the default for all unit tests. Only switch to Loose for specific setups after careful deliberation, and add a comment explaining why.
×

Not awaiting async mock methods in the SUT

Symptom
Unit test passes, but in production the method runs synchronously, potentially deadlocking or returning incomplete results. The mock's ReturnsAsync never fires.
Fix
Ensure the SUT has 'await' before every call to an async method on a mocked dependency. Use analyzers like 'CA2007' to catch missing awaits during compilation.
×

Using SetupSequence without a fallback for extra calls

Symptom
If the production code calls the method more times than the sequence provides, Moq throws an exception at runtime, even in Loose mode. This often happens during retries or edge cases.
Fix
Always add a terminal .Returns() at the end of the sequence, or use a .Callback to track call count and conditionally return values from a list.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Explain the difference between MockBehavior.Loose and MockBehavior.Stric...
Q02SENIOR
How do you mock a method that takes an out parameter in Moq? Provide an ...
Q03SENIOR
What is the difference between Verify() and VerifyAll() in Moq? When sho...
Q01 of 03SENIOR

Explain the difference between MockBehavior.Loose and MockBehavior.Strict in Moq. When would you choose one over the other?

ANSWER
Loose (default) returns default values for any method not explicitly set up — no exception is thrown. This speeds up test creation but risks hiding missing setups that would cause NullReferenceException in production. Strict throws a MockException when any unset method is called, forcing the developer to add a Setup. This makes tests safer but more brittle to interface changes. I start with Strict for critical interfaces (e.g., database repositories) and use Loose for logging or utility interfaces where I don't care about exact calls. In CI, I run the test suite with both behaviors at least once to catch discrepancies.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
What's the difference between Moq and a handwritten fake?
02
Can Moq mock static methods or sealed classes?
03
How do I mock a method that returns Task of IEnumerable but the implementation returns an empty list?
N
Naren Founder & Principal Engineer

20+ years shipping production .NET services in enterprise systems. Lessons pulled from things that broke in production.

Follow
Verified
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
🔥

That's Testing. Mark it forged?

5 min read · try the examples if you haven't

Previous
Unit Testing in C# with xUnit
2 / 5 · Testing
Next
Integration Testing in ASP.NET Core