SimplyMock 1.3.3
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package SimplyMock --version 1.3.3
NuGet\Install-Package SimplyMock -Version 1.3.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SimplyMock" Version="1.3.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SimplyMock" Version="1.3.3" />
<PackageReference Include="SimplyMock" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SimplyMock --version 1.3.3
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: SimplyMock, 1.3.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=SimplyMock&version=1.3.3
#tool nuget:?package=SimplyMock&version=1.3.3
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
SimplyMock
A lightweight .NET method mocking library that allows you to dynamically replace methods and properties implementation in unit tests without creating full mock objects.
Features
- Mock any method's return value with a simple API
- Support for methods with various parameter counts (0-5 parameters)
- Parameter mapping mode to return predefined results based on input parameters
- Property getter mocking support
- Mock exception-throwing behavior
- Async method mocking support
- Static method and static async method mocking
- Generic method mocking support
- Automatic cleanup of all mocks (implements IDisposable)
Limitations
- Each method can only be mocked once, subsequent mocks will throw an error
- Methods with
in
,out
, andref
parameter modifiers are not supported
Basic Usage
1. Create IMethodMocker instance
// Create an instance in your test class constructor
private readonly IMethodMocker _methodMocker;
public YourTestClass()
{
_methodMocker = new MethodMocker();
}
// Release resources in the test class destructor
public void Dispose()
{
_methodMocker.Dispose();
}
2. Mock method return values
// Mock a parameterless method
_methodMocker.MockMethodReturn<string>(
typeof(YourClass),
"GetMessage",
() => "Mocked message"
);
// Mock a method with parameters
_methodMocker.MockMethodReturn<int, string>(
typeof(YourClass),
"GetById",
(id) => $"Mocked item {id}"
);
// Mock a multi-parameter method
_methodMocker.MockMethodReturn<string, int, bool, string>(
typeof(YourClass),
"ProcessData",
(name, code, isEnabled) => $"Processed: {name}"
);
3. Use parameter mapping
// Create input parameter to return value mapping
var resultMap = new Dictionary<string, int>
{
{ "apple", 10 },
{ "banana", 20 },
{ "orange", 15 }
};
// Apply the mapping
_methodMocker.MockMethodReturnMap<string, int>(
typeof(FruitService),
"GetPrice",
resultMap
);
// Now FruitService.GetPrice will return values based on the parameter
// If parameter is not defined in the mapping, it will throw KeyNotFoundException
4. Mock properties
// Mock property getter
_methodMocker.MockPropertyGetter<bool>(
typeof(User),
"IsAdmin",
() => true
);
5. Mock async methods
// Mock parameterless async method
_methodMocker.MockAsyncMethodReturn<string>(
typeof(DataService),
"GetDataAsync",
async () => {
// Real async logic can be performed here
await Task.Delay(10);
return "Mocked async data";
}
);
// Mock async method with parameters
_methodMocker.MockAsyncMethodReturn<string, int>(
typeof(OrderService),
"ProcessOrderAsync",
async (orderId) => {
await Task.Delay(5);
return orderId.Length * 10;
}
);
6. Mock generic methods
// Mock a generic static method with no parameters
// Generic method: public static T Get<T>()
_methodMocker.MockGenericStaticMethodReturn<Person>(
typeof(ServiceFactory),
"Get",
() => new Person {
Name = "John Doe",
Age = 30
}
);
// Mock a generic static method with one parameter
// Generic method: public static T Map<T>(object source)
_methodMocker.MockGenericStaticMethodReturn<UserDto, object>(
typeof(Mapper),
"Map",
src => new UserDto {
Id = 1001,
Username = "johndoe",
Email = "john@example.com"
}
);
// Using the mocked generic methods
Person person = ServiceFactory.Get<Person>();
UserDto userDto = Mapper.Map<UserDto>(sourceObject);
7. Dynamically control static generic method return values with an external variable
Sometimes you may want to flexibly change the return value of a static generic method during your test. You can achieve this by combining an external static variable with a mock:
// Define a static class to control the return value externally
// The MockReturn<T> class now automatically uses the type's full name as the key
// This allows different types to have separate instances without manual naming
public static class MockReturn<T>
{
private static readonly Dictionary<string, T> _instances = new();
private static readonly object _lock = new();
/// <summary>
/// Gets the automatic name based on the type's full name
/// </summary>
private static string GetTypeName()
{
return typeof(T).FullName ?? typeof(T).Name;
}
public static T GetInstance(string name)
{
lock (_lock)
{
_instances.TryGetValue(name, out var instance);
return instance;
}
}
public static void SetInstance(string name, T instance)
{
lock (_lock)
{
_instances[name] = instance;
}
}
/// <summary>
/// Gets instance using the type's full name as the key
/// This automatically separates different types without manual naming
/// </summary>
public static T GetInstance()
{
return GetInstance(GetTypeName());
}
/// <summary>
/// Sets instance using the type's full name as the key
/// This automatically separates different types without manual naming
/// </summary>
public static void SetInstance(T instance)
{
SetInstance(GetTypeName(), instance);
}
public static IEnumerable<string> GetAllNames()
{
lock (_lock)
{
return _instances.Keys.ToList();
}
}
}
// Example static generic method
public static class StaticProvider
{
public static T Get<T>() => default;
}
public class StaticMethodMock_ExternalVariable_Tests : IDisposable
{
private readonly IMethodMocker _methodMocker;
public StaticMethodMock_ExternalVariable_Tests()
{
_methodMocker = new MethodMocker();
}
public void Dispose()
{
_methodMocker.Dispose();
}
[Fact]
public void Mock_StaticGenericMethod_Returns_ExternalVariable()
{
// Arrange - Now you can set instances for different types automatically
var expectedString = "Hello, Mock!";
var expectedInt = 42;
// Each type automatically gets its own instance based on type name
MockReturn<string>.SetInstance(expectedString);
MockReturn<int>.SetInstance(expectedInt);
// Mock the static generic method to return the external variable
_methodMocker.MockGenericStaticMethodReturn<string>(
typeof(StaticProvider),
"Get",
() => MockReturn<string>.GetInstance()
);
_methodMocker.MockGenericStaticMethodReturn<int>(
typeof(StaticProvider),
"Get",
() => MockReturn<int>.GetInstance()
);
// Act & Assert - Different types return their respective values
Assert.Equal("Hello, Mock!", StaticProvider.Get<string>());
Assert.Equal(42, StaticProvider.Get<int>());
// Change the external variable and call again
MockReturn<string>.SetInstance("Changed!");
MockReturn<int>.SetInstance(100);
Assert.Equal("Changed!", StaticProvider.Get<string>());
Assert.Equal(100, StaticProvider.Get<int>());
}
[Fact]
public void Mock_StaticGenericMethod_SupportsNamedInstances()
{
// You can still use named instances for more complex scenarios
MockReturn<string>.SetInstance("scenario1", "First scenario");
MockReturn<string>.SetInstance("scenario2", "Second scenario");
// Mock different behaviors based on named instances
_methodMocker.MockGenericStaticMethodReturn<string>(
typeof(StaticProvider),
"Get",
() => MockReturn<string>.GetInstance("scenario1")
);
Assert.Equal("First scenario", StaticProvider.Get<string>());
// Switch to different scenario
_methodMocker.MockGenericStaticMethodReturn<string>(
typeof(StaticProvider),
"Get",
() => MockReturn<string>.GetInstance("scenario2")
);
Assert.Equal("Second scenario", StaticProvider.Get<string>());
}
}
Advanced Usage
Mock exceptions
// Mock method to throw exceptions
_methodMocker.MockMethodReturn<string, string>(
typeof(UserService),
"GetUserName",
(userId) => {
if (string.IsNullOrEmpty(userId))
throw new ArgumentNullException(nameof(userId));
if (userId == "invalid")
throw new InvalidOperationException("User not found");
return $"User {userId}";
}
);
Notes
- Ensure you call
Dispose()
after tests to release all mocks - When mocking methods, parameter types and count must match exactly
- When using
MockMethodReturnMap
, undefined parameter combinations will throwKeyNotFoundException
- Async method mocking supports real async operations, you can use
await
in replacement functions - SimplyMock supports methods with up to 5 parameters, for both sync and async methods
- Static methods and static async methods are mocked the same way as instance methods
- Generic static methods can be mocked by providing a Func delegate directly
- Multiple mocks on the same method will override previous implementations
- SimplyMock modifies method behavior at runtime, making it ideal for testing legacy code or third-party libraries
Complete Example
using System;
using Xunit;
using SimplyMock;
public class CalculatorService
{
public int Add(int a, int b) => a + b;
}
public class CalculatorTests : IDisposable
{
private readonly IMethodMocker _methodMocker;
public CalculatorTests()
{
_methodMocker = new MethodMocker();
}
public void Dispose()
{
_methodMocker.Dispose();
}
[Fact]
public void Add_ShouldReturnMockedResult()
{
// Replace the implementation of Add method
_methodMocker.MockMethodReturn<int, int, int>(
typeof(CalculatorService),
"Add",
(a, b) => a * b // Replace with multiplication
);
var calculator = new CalculatorService();
int result = calculator.Add(5, 3);
// Now Add method performs multiplication
Assert.Equal(15, result);
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net6.0
- Lib.Harmony (>= 5.1.4)
- MonoMod.RuntimeDetour.HookGen (>= 22.7.31.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.