Skip to content

Migrate documentation samples to NUnit4 #889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* [UPDATE] Migrate documentation validation from build.fsproj to Roslyn code generator
* [NEW] Added NuGet Package README file.
* [UPDATE] Make public api and tests the same for all TFMs
* [UPDATE] Migrate documentation samples to NUnit4

### 5.3.0 (October 2024)

Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,7 @@ Assert.That(eventWasRaised);

NSubstitute and its tests can be compiled and run using Visual Studio, Visual Studio Code or any other editor with .NET support. Note that some tests are marked `[Pending]` and are not meant to pass at present, so it is a good idea to exclude tests in the Pending category from test runs.

There are also build scripts in the `./build` directory for command line builds, and CI configurations in the project root.

To do [full builds](https://github.com/nsubstitute/NSubstitute/wiki/Release-procedure) you'll also need Ruby, as the jekyll gem is used to generate the website.
Release-procedure https://github.com/nsubstitute/NSubstitute/wiki/Release-procedure

### Other libraries you may be interested in

Expand Down
6 changes: 3 additions & 3 deletions acknowledgements.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ The aim of this file is to acknowledge the software projects that have been used
# Software distributed with/compiled into NSubstitute

## Castle.Core
NSubstitute is built on the Castle.Core library, particularly Castle.DynamicProxy which is used for generating proxies for types and intercepting calls made to them so that NSubstitute can record them.
NSubstitute is built on the Castle.Core library, particularly Castle.DynamicProxy which is used for generating proxies for types and intercepting calls made to them so that NSubstitute can record them.

Castle.Core is maintained by the Castle Project [https://www.castleproject.org/] and is released under the Apache License, Version 2.0 [https://www.apache.org/licenses/LICENSE-2.0.html].

Expand All @@ -19,13 +19,13 @@ Used for mocking parts of the NSubstitute mocking library for testing. It is dis
Moq is not directly used in NSubstitute, but was a great source of inspiration. Moq pioneered Arrange-Act-Assert (AAA) mocking syntax for .NET, as well as removing the distinction between mocks and stubs, both of which have become important parts of NSubstitute. Moq is available under the BSD license [https://www.opensource.org/licenses/bsd-license.php].

## Jekyll [https://jekyllrb.com/]
Static website generator written in Ruby, used for NSubstitute's website and documentation. Distributed under the MIT license [https://www.opensource.org/licenses/bsd-license.php].
Static website generator written in Ruby, used for NSubstitute's website and documentation. Distributed under the MIT license [https://www.opensource.org/licenses/bsd-license.php]. No longer used since migration to docfx.

## SyntaxHighlighter [https://alexgorbatchev.com/SyntaxHighlighter/]
Open source, JavaScript, client-side code highlighter used for highlighting code samples on the NSubstitute website. Distributed under the MIT License [https://en.wikipedia.org/wiki/MIT_License] and the GPL [https://www.gnu.org/copyleft/lesser.html].

## FAKE [https://fsharp.github.io/FAKE/]
FAKE (F# Make) is used for NSubstitute's build. It is inspired by `make` and `rake`. FAKE is distributed under a dual Apache 2 / MS-PL license [https://github.com/fsharp/FAKE/blob/master/License.txt].
FAKE (F# Make) is used for NSubstitute's build. It is inspired by `make` and `rake`. FAKE is distributed under a dual Apache 2 / MS-PL license [https://github.com/fsharp/FAKE/blob/master/License.txt]. No longer used since migration to source generators.

## Microsoft .NET Framework [https://www.microsoft.com/net/]
NSubstitute is coded in C# and compiled using Microsoft .NET. It can also run and compile under Mono [https://www.mono-project.com], an open source implementation of the open .NET standards for C# and the CLI.
Expand Down
8 changes: 4 additions & 4 deletions docs/help/actions-with-arguments/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ calculator.Multiply(Arg.Any<int>(), Arg.Do<int>(x => argumentUsed = x));

calculator.Multiply(123, 42);

Assert.AreEqual(42, argumentUsed);
Assert.That(argumentUsed, Is.EqualTo(42));
```

Here we specify that a call to `Multiply` with any first argument should pass the second argument and put it in the `argumentUsed` variable. This can be quite useful when we want to assert several properties on an argument (for types more complex than `int` that is).
Expand All @@ -97,7 +97,7 @@ calculator.Multiply(2, 10);
calculator.Multiply(5, 10);
calculator.Multiply(7, 4567); //Will not match our Arg.Do as second arg is not 10

Assert.AreEqual(firstArgsBeingMultiplied, new[] { 2, 5 });
Assert.That(firstArgsBeingMultiplied, Is.EqualTo(new[] { 2, 5 }));
```

Here our `Arg.Do` takes whatever `int` is passed as the first argument to `Multiply` and adds it to a list whenever the second argument is 10.
Expand All @@ -124,6 +124,6 @@ var results = new[] {
calculator.Multiply(123, 2) //First arg greater than 0, so spec won't be met.
};

Assert.AreEqual(3, numberOfCallsWhereFirstArgIsLessThan0); //3 of 4 calls have first arg < 0
Assert.AreEqual(results, new[] {123, 123, 123, 0}); //Last call returns 0, not 123
Assert.That(3, Is.EqualTo(numberOfCallsWhereFirstArgIsLessThan0)); //3 of 4 calls have first arg < 0
Assert.That(results, Is.EqualTo(new[] {123, 123, 123, 0})); //Last call returns 0, not 123
```
22 changes: 11 additions & 11 deletions docs/help/argument-matchers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ An argument of type `T` can be ignored using `Arg.Any<T>()`.
```csharp
calculator.Add(Arg.Any<int>(), 5).Returns(7);

Assert.AreEqual(7, calculator.Add(42, 5));
Assert.AreEqual(7, calculator.Add(123, 5));
Assert.AreNotEqual(7, calculator.Add(1, 7));
Assert.That(calculator.Add(42, 5), Is.EqualTo(7));
Assert.That(calculator.Add(123, 5), Is.EqualTo(7));
Assert.That(calculator.Add(1, 7), Is.Not.EqualTo(7));
```

In this example we return `7` when adding any number to `5`. We use `Arg.Any<int>()` to tell NSubstitute to ignore the first argument.
Expand Down Expand Up @@ -87,11 +87,11 @@ If the condition throws an exception for an argument, then it will be assumed th
```csharp
formatter.Format(Arg.Is<string>(x => x.Length <= 10)).Returns("matched");

Assert.AreEqual("matched", formatter.Format("short"));
Assert.AreNotEqual("matched", formatter.Format("not matched, too long"));
Assert.That(formatter.Format("short"), Is.EqualTo("matched"));
Assert.That(formatter.Format("not matched, too long"), Is.Not.EqualTo("matched"));
// Will not match because trying to access .Length on null will throw an exception when testing
// our condition. NSubstitute will assume it does not match and swallow the exception.
Assert.AreNotEqual("matched", formatter.Format(null));
Assert.That(formatter.Format(null), Is.Not.EqualTo("matched"));
```

## Matching a specific argument
Expand Down Expand Up @@ -121,8 +121,8 @@ calculator
});

var hasEntry = calculator.LoadMemory(1, out var memoryValue);
Assert.AreEqual(true, hasEntry);
Assert.AreEqual(42, memoryValue);
Assert.That(hasEntry, Is.EqualTo(true));
Assert.That(memoryValue, Is.EqualTo(42));
```

See [Setting out and ref args](/help/setting-out-and-ref-arguments/) for more information on working with `out` and `ref`.
Expand Down Expand Up @@ -204,8 +204,8 @@ widgetFactory.Make(Arg.Do<WidgetInfo>(info => testLog2.Add(info.Name)));
subject.StartWithWidget(new WidgetInfo { Name = "Test Widget" });

/* ASSERT */
Assert.AreEqual(new[] { "Test Widget" }, testLog);
Assert.AreEqual(new[] { "Test Widget" }, testLog2);
Assert.That(testLog, Is.EqualTo(new[] { "Test Widget" }));
Assert.That(testLog2, Is.EqualTo(new[] { "Test Widget" }));
```

### Modifying values being matched
Expand Down Expand Up @@ -288,7 +288,7 @@ public void ManualArgSnapshot() {
lookup.Add(person);
person.Name = "Vimes";

Assert.AreEqual("Carrot", namesAdded[0]);
Assert.That(namesAdded[0], Is.EqualTo("Carrot"));
}
```

Expand Down
23 changes: 12 additions & 11 deletions docs/help/auto-and-recursive-mocks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ var parser = Substitute.For<INumberParser>();
factory.Create(',').Returns(parser);
parser.Parse("an expression").Returns(new[] {1,2,3});

Assert.AreEqual(
Assert.That(
factory.Create(',').Parse("an expression"),
new[] {1,2,3});
Is.EqualTo(new[] {1,2,3}));
```

Or we could use the fact that a substitute for type `INumberParser` will automatically be returned for `INumberParserFactory.Create()`:
Expand All @@ -38,9 +38,9 @@ Or we could use the fact that a substitute for type `INumberParser` will automat
var factory = Substitute.For<INumberParserFactory>();
factory.Create(',').Parse("an expression").Returns(new[] {1,2,3});

Assert.AreEqual(
Assert.That(
factory.Create(',').Parse("an expression"),
new[] {1,2,3});
Is.EqualTo(new[] {1,2,3}));
```

Each time a recursively-subbed property or method is called with the same arguments it will return the same substitute. If a method is called with different arguments a new substitute will be returned.
Expand All @@ -57,8 +57,8 @@ var firstCall = factory.Create(',');
var secondCall = factory.Create(',');
var thirdCallWithDiffArg = factory.Create('x');

Assert.AreSame(firstCall, secondCall);
Assert.AreNotSame(firstCall, thirdCallWithDiffArg);
Assert.That(firstCall, Is.SameAs(secondCall));
Assert.That(firstCall, Is.Not.SameAs(thirdCallWithDiffArg));
```

_Note:_ Recursive substitutes will not be created for non-purely virtual classes, as creating and using classes can have potentially unwanted side-effects. You'll therefore need to create and return these explicitly.
Expand Down Expand Up @@ -86,9 +86,9 @@ To get the identity of the `CurrentRequest` to return a certain name, we could m
```csharp
var context = Substitute.For<IContext>();
context.CurrentRequest.Identity.Name.Returns("My pet fish Eric");
Assert.AreEqual(
"My pet fish Eric",
context.CurrentRequest.Identity.Name);
Assert.That(
context.CurrentRequest.Identity.Name,
Is.EqualTo("My pet fish Eric"));
```

Here `CurrentRequest` is automatically going to return a substitute for `IRequest`, and the `IRequest` substitute will automatically return a substitute for `IIdentity`.
Expand All @@ -100,6 +100,7 @@ Properties and methods returning types of `String` or `Array` will automatically

```csharp
var identity = Substitute.For<IIdentity>();
Assert.AreEqual(String.Empty, identity.Name);
Assert.AreEqual(0, identity.Roles().Length);

Assert.That(identity.Name, Is.EqualTo(String.Empty));
Assert.That(identity.Roles().Length, Is.EqualTo(0));
```
8 changes: 4 additions & 4 deletions docs/help/callbacks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ calculator
calculator.Add(7, 3);
calculator.Add(2, 2);
calculator.Add(11, -3);
Assert.AreEqual(counter, 3);
Assert.That(counter, Is.EqualTo(3));
```

The [Return from a function](/help/return-from-function) topic has more information on the arguments passed to the callback.
Expand All @@ -51,7 +51,7 @@ public void SayHello() {

foo.SayHello("World");
foo.SayHello("World");
Assert.AreEqual(2, counter);
Assert.That(counter, Is.EqualTo(2));
}
```

Expand All @@ -67,8 +67,8 @@ calculator
.Do(x => counter++);

var result = calculator.Add(1, 2);
Assert.AreEqual(3, result);
Assert.AreEqual(1, counter);
Assert.That(result, Is.EqualTo(3));
Assert.That(counter, Is.EqualTo(1));
```

## Per argument callbacks
Expand Down
2 changes: 1 addition & 1 deletion docs/help/configure/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ calculator.Add(Arg.Any<int>(), Arg.Any<int>()).Returns(x => { throw new Exceptio
calculator.Configure().Add(1, 2).Returns(3);

// Now both the exception callback and our other return have been configured:
Assert.AreEqual(3, calculator.Add(1, 2));
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));
Assert.Throws<Exception>(() => calculator.Add(-2, -2));
```

Expand Down
8 changes: 4 additions & 4 deletions docs/help/creating-a-substitute/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ var substitute = Substitute.For(
new[] { typeof(ICommand), typeof(ISomeInterface), typeof(SomeClassWithCtorArgs) },
new object[] { 5, "hello world" }
);
Assert.IsInstanceOf<ICommand>(substitute);
Assert.IsInstanceOf<ISomeInterface>(substitute);
Assert.IsInstanceOf<SomeClassWithCtorArgs>(substitute);
Assert.That(substitute, Is.InstanceOf<ICommand>());
Assert.That(substitute, Is.InstanceOf<ISomeInterface>());
Assert.That(substitute, Is.InstanceOf<SomeClassWithCtorArgs>());
```

<!--
Expand Down Expand Up @@ -92,7 +92,7 @@ NSubstitute can also substitute for delegate types by using `Substiute.For<T>()`
var func = Substitute.For<Func<string>>();

func().Returns("hello");
Assert.AreEqual("hello", func());
Assert.That(func(), Is.EqualTo("hello"));
```

## Partial substitutes and test spies
Expand Down
10 changes: 5 additions & 5 deletions docs/help/multiple-returns/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ A call can also be configured to return a different value over multiple calls. T

```csharp
calculator.Mode.Returns("DEC", "HEX", "BIN");
Assert.AreEqual("DEC", calculator.Mode);
Assert.AreEqual("HEX", calculator.Mode);
Assert.AreEqual("BIN", calculator.Mode);
Assert.That(calculator.Mode, Is.EqualTo("DEC"));
Assert.That(calculator.Mode, Is.EqualTo("HEX"));
Assert.That(calculator.Mode, Is.EqualTo("BIN"));
```

This can also be achieved by [returning from a function](/help/return-from-function), but passing multiple values to `Returns()` is simpler and reads better.
Expand All @@ -30,8 +30,8 @@ This can also be achieved by [returning from a function](/help/return-from-funct

```csharp
calculator.Mode.Returns(x => "DEC", x => "HEX", x => { throw new Exception(); });
Assert.AreEqual("DEC", calculator.Mode);
Assert.AreEqual("HEX", calculator.Mode);
Assert.That(calculator.Mode, Is.EqualTo("DEC"));
Assert.That(calculator.Mode, Is.EqualTo("HEX"));
Assert.Throws<Exception>(() => { var result = calculator.Mode; });
```

Expand Down
8 changes: 4 additions & 4 deletions docs/help/raising-events/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ engine.Idling += (sender, args) => wasCalled = true;
//Tell the substitute to raise the event with a sender and EventArgs:
engine.Idling += Raise.EventWith(new object(), new EventArgs());

Assert.True(wasCalled);
Assert.That(wasCalled);
```

In the example above we don't really mind what sender and `EventArgs` our event is raised with, just that it was called. In this case NSubstitute can make our life easier by creating the required arguments for our event handler:

```csharp
engine.Idling += Raise.Event();
Assert.True(wasCalled);
Assert.That(wasCalled, Is.True);
```

## Raising events when arguments do not have a default constructor
Expand All @@ -64,7 +64,7 @@ engine.LowFuelWarning += Raise.EventWith(new LowFuelWarningEventArgs(10));
//Raise event with specific args and sender:
engine.LowFuelWarning += Raise.EventWith(new object(), new LowFuelWarningEventArgs(10));

Assert.AreEqual(2, numberOfEvents);
Assert.That(numberOfEvents, Is.EqualTo(2));
```

## Raising `Delegate` events
Expand Down Expand Up @@ -93,5 +93,5 @@ engine.RevvedAt += rpm => revvedAt = rpm;

engine.RevvedAt += Raise.Event<Action<int>>(123);

Assert.AreEqual(123, revvedAt);
Assert.That(revvedAt, Is.EqualTo(123));
```
2 changes: 1 addition & 1 deletion docs/help/replacing-return-values/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ calculator.Mode.Returns("DEC,HEX,OCT");
calculator.Mode.Returns(x => "???");
calculator.Mode.Returns("HEX");
calculator.Mode.Returns("BIN");
Assert.AreEqual(calculator.Mode, "BIN");
Assert.That(calculator.Mode, Is.EqualTo("BIN"));
```

<!--
Expand Down
4 changes: 2 additions & 2 deletions docs/help/return-for-any-args/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ A call can be configured to return a value regardless of the arguments passed us

```csharp
calculator.Add(1, 2).ReturnsForAnyArgs(100);
Assert.AreEqual(100, calculator.Add(1, 2));
Assert.AreEqual(100, calculator.Add(-7, 15));
Assert.That(calculator.Add(1, 2), Is.EqualTo(100));
Assert.That(calculator.Add(-7, 15), Is.EqualTo(100));
```

**Tip!** You can also use the `default` C# keyword for better readability:
Expand Down
12 changes: 6 additions & 6 deletions docs/help/return-for-args/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ Return values can be configured for different combinations of arguments passed t
```csharp
//Return when first arg is anything and second arg is 5:
calculator.Add(Arg.Any<int>(), 5).Returns(10);
Assert.AreEqual(10, calculator.Add(123, 5));
Assert.AreEqual(10, calculator.Add(-9, 5));
Assert.AreNotEqual(10, calculator.Add(-9, -9));
Assert.That(calculator.Add(123, 5), Is.EqualTo(10));
Assert.That(calculator.Add(-9, 5), Is.EqualTo(10));
Assert.That(calculator.Add(-9, -9), Is.Not.EqualTo(10));

//Return when first arg is 1 and second arg less than 0:
calculator.Add(1, Arg.Is<int>(x => x < 0)).Returns(345);
Assert.AreEqual(345, calculator.Add(1, -2));
Assert.AreNotEqual(345, calculator.Add(1, 2));
Assert.That(345, Is.EqualTo(calculator.Add(1, -2)));
Assert.That(calculator.Add(1, 2), Is.Not.EqualTo(345));

//Return when both args equal to 0:
calculator.Add(Arg.Is(0), Arg.Is(0)).Returns(99);
Assert.AreEqual(99, calculator.Add(0, 0));
Assert.That(99, Is.EqualTo(calculator.Add(0, 0)));
```
4 changes: 2 additions & 2 deletions docs/help/return-from-function/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ calculator
calculator.Add(7,3);
calculator.Add(2,2);
calculator.Add(11,-3);
Assert.AreEqual(counter, 3);
Assert.That(counter, Is.EqualTo(3));
```

Alternatively the callback can be specified after the `Returns` using `AndDoes`:
Expand All @@ -77,5 +77,5 @@ calculator

calculator.Add(7,3);
calculator.Add(2,2);
Assert.AreEqual(counter, 2);
Assert.That(counter, Is.EqualTo(2));
```
10 changes: 5 additions & 5 deletions docs/help/set-return-value/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ This value will be returned every time this call is made. `Returns()` will only
```csharp
//Make a call return 3:
calculator.Add(1, 2).Returns(3);
Assert.AreEqual(calculator.Add(1, 2), 3);
Assert.AreEqual(calculator.Add(1, 2), 3);
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));

//Call with different arguments does not return 3
Assert.AreNotEqual(calculator.Add(3, 6), 3);
Assert.That(calculator.Add(3, 6), Is.Not.EqualTo(3));
```

## For properties
The return value for a property can be set in the same way as for a method, using `Returns()`. You can also just use plain old property setters for read/write properties; they'll behave just the way you expect them to.

```csharp
calculator.Mode.Returns("DEC");
Assert.AreEqual(calculator.Mode, "DEC");
Assert.That("DEC", Is.EqualTo(calculator.Mode));

calculator.Mode = "HEX";
Assert.AreEqual(calculator.Mode, "HEX");
Assert.That("HEX", Is.EqualTo(calculator.Mode));
```


Expand Down
Loading
Loading