FunctionalDev.MoqHelpers
2.0.15
See the version list below for details.
dotnet add package FunctionalDev.MoqHelpers --version 2.0.15
NuGet\Install-Package FunctionalDev.MoqHelpers -Version 2.0.15
<PackageReference Include="FunctionalDev.MoqHelpers" Version="2.0.15" />
paket add FunctionalDev.MoqHelpers --version 2.0.15
#r "nuget: FunctionalDev.MoqHelpers, 2.0.15"
// Install FunctionalDev.MoqHelpers as a Cake Addin #addin nuget:?package=FunctionalDev.MoqHelpers&version=2.0.15 // Install FunctionalDev.MoqHelpers as a Cake Tool #tool nuget:?package=FunctionalDev.MoqHelpers&version=2.0.15
FunctionalDev.MoqHelpers
Moq Helpers is a library which has been created to aid unit testing.
Please read through the rest of this document to view tools which can help reduce the brittle nature of unit tests, decrease excess code when setting up objects and enhance the clarity of what it is you're testing.
A particular focus of this library is setting up Mock objects (including non-public members) and providing access to non-public members and methods of instantiated objects.
Activators
Creating instances of objects is central to most unit testing. Activator classes have been provided to reduce the overhead and brittle nature of setting up classes, when it may not be required to provide all arguments for the constructor, if those arguments are not necessary for the particular unit test in focus.
These activators can be used to future-proof the creation of objects, in that future changes to an object constructor will not break existing unit tests, providing that the additional arguments do not affect existing behaviour.
Lazy Mock Activation
A MockActivator
class can be used to create Mock{T}
classes.
This activator has CreateLazy
and CreateNull
methods which allow the creation of Mock{T} classes without needing to provide all/any constructor arguments.
Whilst these methods can be used to provide all arguments, they can also be provided with some or all constructor arguments to enable future-proofing with future constructor signature changes.
Given the following class:
public abstract class Person
{
protected Person(ILogger<Person> logger) { }
}
The following example uses CreateLazy, without arguments, to create a new instance of Mock{Person} without supplying an instance of ILogger{Person}. Note that the Person base type will be supplied new Mock{ILogger {Person}}.Object as a value for ILogger{Person}.
public Mock<Person> CreateLazy()
=> MockActivator.CreateLazy<Person>();
The following example uses CreateNull, without arguments, to create a new instance of Mock{Person} without supplying an instance of ILogger{Person}. Note that the Person base type will be supplied null as a value for ILogger{Person}.
public Mock<Person> CreateNull()
=> MockActivator.CreateNull<Person>();
The following example uses CreateLazy, with arguments, to create a new instance of Mock{Person} supplying an instance of Mock{ILogger{Person}}. Note that the Person base type will be supplied loggerMock.Object as a value for ILogger{Person}.
public Mock<Person> CreateLazyWithMockArgument(Mock<ILogger<Person>> loggerMock)
=> MockActivator.CreateLazy<Person>(loggerMock);
The following example uses CreateLazy, with arguments, to create a new instance of Mock{Person} supplying an instance of ILogger{Person}. Note that the Person base type will be supplied loggerInstance as a value for ILogger{Person}.
public Mock<Person> CreateLazyWithMockArgument(ILogger<Person> loggerInstance)
=> MockActivator.CreateLazy<Person>(loggerInstance);
Lazy Activation
A LazyActivator
class can be used to create instances of concrete classes.
This activator has CreateLazy
and CreateNull
methods which allow the creation of concrete classes without needing to provide all/any constructor arguments.
Whilst these methods can be used to provide all arguments, they can also be provided with some or all constructor arguments to enable future-proofing with future constructor signature changes.
An example can be seen below:
public class Person
{
public Person(ILogger<Person> logger) { }
}
The following example uses CreateLazy, without arguments, to create a new instance of Person without supplying an instance of ILogger{Person}. Note that the Person constructor will be supplied new Mock{ILogger{Person}}.Object as a value for ILogger{Person}.
public Person CreateLazy()
=> LazyActivator.CreateLazy<Person>();
The following example uses CreateNull, without arguments, to create a new instance of Person without supplying an instance of ILogger{Person}. Note that the Person constructor will be supplied null as a value for ILogger{Person}.
public Person CreateNull()
=> LazyActivator.CreateNull<Person>();
The following example uses CreateLazy, with arguments, to create a new instance of Person supplying an instance ofMock{ILogger{Person}}. Note that the Person constructor will be supplied loggerMock.Object as a value for ILogger{Person}.
public Person CreateLazyWithMockArgument(Mock<ILogger<Person>> loggerMock)
=> LazyActivator.CreateLazy<Person>(loggerMock);
The following example uses CreateLazy, with arguments, to create a new instance of Person supplying an instance of ILogger{Person}. Note that the Person constructor will be supplied loggerInstance as a value for ILogger{Person}.
public Person CreateLazyWithMockArgument(ILogger<Person> loggerInstance)
=> LazyActivator.CreateLazy<Person>(loggerInstance);
Container Creation
Container Lazy and Mock activation has been added to provide a means of extracted auto loaded construction objects. Please note that whilst this example uses MockActivator
this is also present in LazyActivator
.
private readonly TestClass _testClass;
private readonly Mock<ILogger<TestClass>> _loggerMock;
private readonly Mock<IWidget> _widgetMock;
private readonly IWidget _widget;
public UnitTest()
{
var container = MockActivator.CreateLazyContainer<TestClass>();
_testClass = container.Instance.Object;
_loggerMock = container.GetArgumentAsMock<ILogger<TestClass>>();
_widgetMock = container.GetArgumentAsMock<IWidget>();
_widget = container.GetArgument<IWidget>();
}
Object Proxy
The ObjectProxy
class can be used to interact (set/get) private members of a given instance, and can be used to invoke protected/private methods.
Dot separated member access is supported to access members of members recursively. E.g. ObjectProxy.For(person)["Name"."FirstName"]
Static classes can be setup with ObjectProxy.ForStatic
to interact with static classes.
Examples
Given the following class:
public class Person
{
private string Name { set; get; }
private Person(ILogger<Person> logger, string name)
{
Name = name;
}
private string GetName()
=> Name;
private string ToStringFor<T>(T arg)
=> arg.ToString();
}
Creating an instance of Person
can be achieved as shown below.
var person = LazyActivator.CreateLazy<Person>("Fred");
// or
var person = LazyActivator.CreateLazy<Person>();
And members can be managed as shown below.
// Get.
var name = ObjectProxy.For(person)["Name"];
// Set.
ObjectProxy.For(person)["Name"] = "Bob";
Methods can be invoked via the proxy with:
var result = person.InvokeMethod<string>("GetName");
For full examples please see end of this file.
Setup Extension Methods
Several extension methods have been provided which enable functional Moq creation (returning Mock{T}
to enable chaining) and to setup private/protected members.
Please note that to resovle the extension methods, it may be required to add the following using statement:
using FunctionalDev.MoqHelpers;
Please also note that the extension methods are not the typical .Setup(...).Returns(...)
format. For simple method setups the format this library provides is:
.Setup(type => type.MethodName, Expression<Func<InputArgs, ReturnArg>>);
Given an example interface:
public interface IPerson
{
string SetName(string name);
int GetAge();
}
The following can be used to set up an IPerson
interface.
var person = new Mock<IPerson>()
.Setup(x => x.SetName, (string name) => "")
.Setup(x => x.GetAge, () => 25);
Please note that this does not provide any filters on the arguments for methods (such as It.Is<T>(Func<T, bool>)
filtering).
Full Example
public abstract record FullExampleObjectBase(ILogger<FullExampleObjectBase> Logger)
{
public ILogger<FullExampleObjectBase> Logger { get; } = Logger;
private int _localIntegerValue = 1;
protected virtual string GetName()
=> nameof(FullExampleObjectBase);
private void SetLocalIntegerValue(int newValue)
{
_localIntegerValue = newValue;
}
private int GetLocalIntegerValue()
=> _localIntegerValue;
private int GenericMethod<T>() => 1;
public abstract string GetNameAbstract(string arg);
}
public record FullExampleObject(ILogger<FullExampleObjectBase> Logger)
: FullExampleObjectBase(Logger)
{
public override string GetNameAbstract(string arg)
=> arg;
}
public static class FullExampleStaticClass
{
private static void SetStaticValue(string arg) { }
}
public class FullExample
{
public FullExampleObject CreateFullExampleObject()
=> LazyActivator.CreateLazy<FullExampleObject>();
public FullExampleObject CreateFullExampleObjectWithArgument()
=> LazyActivator.CreateLazy<FullExampleObject>(Mock.Of<ILogger<FullExampleObjectBase>>());
public void SetPrivate()
{
var proxy = ObjectProxy.For(CreateFullExampleObject());
proxy["_localIntegerValue"] = 5;
}
public void GetPrivate()
{
var proxy = ObjectProxy.For(CreateFullExampleObject());
var value = (int)proxy["_localIntegerValue"];
}
private void CallPrivate()
{
var proxy = ObjectProxy.For(CreateFullExampleObject());
proxy.InvokeMethod("SetLocalIntegerValue", 5);
}
private void CallPrivateWithReturning()
{
var proxy = ObjectProxy.For(CreateFullExampleObject());
int resultAsInt = proxy.InvokeMethod<int>("GetLocalIntegerValue");
object resultAsObject = proxy.InvokeMethod("GetLocalIntegerValue");
}
private void CallGenericPrivateMethod()
{
var proxy = ObjectProxy.For(CreateFullExampleObject());
int resultAsInt = proxy.InvokeGenericMethod<int>("GenericMethod", new[] { typeof(RecordClass) }, Array.Empty<object>());
object resultAsObject = proxy.InvokeGenericMethod("GenericMethod", new[] { typeof(RecordClass) }, Array.Empty<object>());
}
private void ObjectProxyForStaticClass()
{
var proxy = ObjectProxy.ForStatic(typeof(FullExampleStaticClass));
proxy.InvokeMethod("SetStaticValue", "Hello world");
}
private void SetupExtensionMethods()
{
MockActivator.CreateLazy<FullExampleObjectBase>()
// Setting members.
.Setup(x => x.Logger, Mock.Of<ILogger<FullExampleObjectBase>>())
// Setting public methods.
.Setup(x => x.GetNameAbstract, (string arg) => arg + "test")
// Setting private methods.
.Setup("GetName", () => "Hello World")
// Also works for public methods.
.Setup("GetNameAbstract", (string arg) => arg + "test")
;
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.1)
- Moq (>= 4.16.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.2.0 | 162 | 9/17/2024 |
3.1.6 | 79 | 7/24/2024 |
3.1.5 | 126 | 7/8/2024 |
3.1.4 | 174 | 2/20/2024 |
3.1.3 | 152 | 1/22/2024 |
3.1.2 | 97 | 1/22/2024 |
3.1.1 | 107 | 1/21/2024 |
3.1.0 | 95 | 1/21/2024 |
3.0.25 | 221 | 12/6/2023 |
3.0.24 | 142 | 12/4/2023 |
3.0.23 | 187 | 11/15/2023 |
3.0.22 | 205 | 10/10/2023 |
3.0.21 | 140 | 10/6/2023 |
3.0.20 | 202 | 8/7/2023 |
3.0.19 | 157 | 7/31/2023 |
3.0.18 | 144 | 7/31/2023 |
3.0.17 | 174 | 6/27/2023 |
3.0.16 | 192 | 6/2/2023 |
3.0.15 | 148 | 6/2/2023 |
3.0.14 | 179 | 5/15/2023 |
3.0.13 | 259 | 4/18/2023 |
3.0.12 | 187 | 4/18/2023 |
3.0.11 | 180 | 4/17/2023 |
3.0.10 | 206 | 4/14/2023 |
3.0.9 | 188 | 4/14/2023 |
3.0.8 | 198 | 4/14/2023 |
3.0.7 | 192 | 4/14/2023 |
3.0.6 | 295 | 2/17/2023 |
3.0.5 | 240 | 2/16/2023 |
3.0.4 | 266 | 2/9/2023 |
3.0.3 | 268 | 2/7/2023 |
3.0.2 | 1,865 | 1/24/2023 |
3.0.1 | 360 | 1/11/2023 |
3.0.0 | 309 | 1/11/2023 |
2.1.4 | 488 | 11/1/2022 |
2.1.3 | 556 | 7/19/2022 |
2.1.2 | 495 | 5/3/2022 |
2.1.1 | 451 | 5/3/2022 |
2.1.0 | 443 | 4/27/2022 |
2.0.15 | 433 | 4/26/2022 |
2.0.14 | 494 | 3/10/2022 |
2.0.13 | 748 | 1/27/2022 |
2.0.12 | 662 | 1/24/2022 |
2.0.11 | 653 | 1/21/2022 |
2.0.10 | 427 | 9/10/2021 |
2.0.9 | 351 | 9/10/2021 |
2.0.8 | 312 | 9/3/2021 |
2.0.7 | 312 | 9/3/2021 |
2.0.6 | 337 | 9/2/2021 |
2.0.5 | 311 | 8/27/2021 |
2.0.4 | 293 | 8/27/2021 |
2.0.3 | 307 | 8/13/2021 |
2.0.2 | 356 | 7/29/2021 |
2.0.1 | 339 | 7/28/2021 |
2.0.0 | 336 | 7/28/2021 |
1.1.0 | 389 | 7/28/2021 |
1.0.0 | 376 | 7/27/2021 |