Last active
August 11, 2023 11:05
-
-
Save martincostello/5760e8b22d43c967d42f8cf6d7d5060e to your computer and use it in GitHub Desktop.
Mocking Moq for NSubstitute
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) Martin Costello, 2023. All rights reserved. | |
// Licensed under the Apache 2.0 license. | |
using System.Linq.Expressions; | |
using NSubstitute.Core; | |
using NSubstitute.ExceptionExtensions; | |
namespace NSubstitute; | |
/// <summary> | |
/// This class acts as a bridge from Moq to NSubstitute to allow it to be removed without too much code churn. | |
/// </summary> | |
public static class NSubstituteExtensions | |
{ | |
public static ConfiguredCall ReturnsAsync<T>(this Task<T> value, T returnThis, params T[] returnThese) | |
{ | |
var task = Task.FromResult(returnThis); | |
var tasks = Array.Empty<Task<T>>(); | |
if (returnThese?.Length > 0) | |
{ | |
tasks = returnThese.Select((p) => Task.FromResult(p)).ToArray(); | |
} | |
return value.Returns(task, tasks); | |
} | |
public static T Setup<T>(this Mock<T> value, Action<T> selector) | |
where T : class | |
{ | |
selector(value.Object); | |
return value.Object; | |
} | |
public static TResult Setup<T, TResult>(this Mock<T> value, Func<T, TResult> selector) | |
where T : class | |
{ | |
return selector(value.Object); | |
} | |
public static TResult Setup<T, TResult>(this T value, Func<T, TResult> selector) | |
{ | |
return selector(value); | |
} | |
public static ConfiguredCall Throws<T>(this Task<T> value, Exception exception) | |
{ | |
return value.Throws((_) => throw exception); | |
} | |
public static ConfiguredCall ThrowsAsync<T>(this Task<T> value, Exception exception) | |
{ | |
return value.Throws((_) => throw exception); | |
} | |
public static void Verify<T>(this Mock<T> value, Action<T> selector) | |
where T : class | |
{ | |
value.Verify(selector, (Times?)null); | |
} | |
public static void Verify<T>(this Mock<T> value, Action<T> selector, Times? times = null) | |
where T : class | |
{ | |
if (times is { } number) | |
{ | |
value.Object.Received(number); | |
} | |
else | |
{ | |
value.Object.Received(); | |
} | |
value.Setup(selector); | |
} | |
public static void Verify<T>(this Mock<T> value, Action<T> selector, Func<Times>? times = null) | |
where T : class | |
{ | |
if (times is { } number) | |
{ | |
value.Object.Received(number()); | |
} | |
else | |
{ | |
value.Object.Received(); | |
} | |
value.Setup(selector); | |
} | |
public static void Verify<T, TResult>(this Mock<T> value, Func<T, TResult> selector, Times? times = null) | |
where T : class | |
{ | |
if (times is { } number) | |
{ | |
value.Object.Received(number); | |
} | |
else | |
{ | |
value.Object.Received(); | |
} | |
value.Setup(selector); | |
} | |
} | |
public readonly struct Times | |
{ | |
private Times(int value) | |
{ | |
Value = value; | |
} | |
private int Value { get; } | |
public static implicit operator int(Times times) => times.Value; | |
public static Times Never() => new(0); | |
public static Times Once() => new(1); | |
public static Times Exactly(int count) => new(count); | |
} | |
public static class It | |
{ | |
public static ref T Is<T>(T value) => ref Arg.Is(value); | |
public static ref T Is<T>(Expression<Predicate<T>> predicate) => ref Arg.Is(predicate); | |
public static ref T IsAny<T>() => ref Arg.Any<T>(); | |
public static ref T IsNotNull<T>() => ref Arg.Is<T>((p) => p != null); | |
public static ref string IsRegex(string pattern) => ref Arg.Is<string>((p) => Regex.IsMatch(p, pattern)); | |
} | |
public static class Mock | |
{ | |
public static T Of<T>(params object[] constructorArguments) | |
where T : class | |
{ | |
return Substitute.For<T>(constructorArguments); | |
} | |
} | |
public class Mock<T> | |
where T : class | |
{ | |
public Mock(params object[] constructorArguments) | |
{ | |
Object = Substitute.For<T>(constructorArguments); | |
} | |
public T Object { get; } | |
public static implicit operator T(Mock<T> mock) => mock.Object; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment