![]() |
VOOZH | about |
dotnet add package SimplyMock --version 1.5.1
NuGet\Install-Package SimplyMock -Version 1.5.1
<PackageReference Include="SimplyMock" Version="1.5.1" />
<PackageVersion Include="SimplyMock" Version="1.5.1" />Directory.Packages.props
<PackageReference Include="SimplyMock" />Project file
paket add SimplyMock --version 1.5.1
#r "nuget: SimplyMock, 1.5.1"
#:package SimplyMock@1.5.1
#addin nuget:?package=SimplyMock&version=1.5.1Install as a Cake Addin
#tool nuget:?package=SimplyMock&version=1.5.1Install as a Cake Tool
A lightweight .NET method mocking library that allows you to dynamically replace methods and properties implementation in unit tests without creating full mock objects.
in, out, and ref parameter modifiers are not supported// 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();
}
// 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 (up to 10 parameters supported)
_methodMocker.MockMethodReturn<string, int, bool, string>(
typeof(YourClass),
"ProcessData",
(name, code, isEnabled) => $"Processed: {name}"
);
// Example with more parameters (6 parameters)
_methodMocker.MockMethodReturn<string, int, bool, DateTime, double, char, string>(
typeof(ComplexService),
"ProcessComplexData",
(name, count, flag, date, value, code) => $"Complex processing: {name}"
);
// Example with maximum parameters (10 parameters)
_methodMocker.MockMethodReturn<string, int, bool, DateTime, double, char, byte, long, float, decimal, string>(
typeof(MaxParamService),
"ProcessMaxParams",
(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"Max params processed"
);
// Single parameter mapping
var resultMap = new Dictionary<string, int>
{
{ "apple", 10 },
{ "banana", 20 },
{ "orange", 15 }
};
_methodMocker.MockMethodReturnMap<string, int>(
typeof(FruitService),
"GetPrice",
resultMap
);
// Multi-parameter mapping with tuples (up to 10 parameters)
var multiParamMap = new Dictionary<(string, int, bool), string>
{
{ ("user1", 25, true), "Active user" },
{ ("user2", 30, false), "Inactive user" }
};
_methodMocker.MockMethodReturnMap<string, int, bool, string>(
typeof(UserService),
"GetUserStatus",
multiParamMap
);
// Complex mapping with many parameters
var complexMap = new Dictionary<(string, int, bool, DateTime, double, char), string>
{
{ ("data", 100, true, DateTime.Now, 3.14, 'A'), "Complex result 1" },
{ ("info", 200, false, DateTime.Today, 2.71, 'B'), "Complex result 2" }
};
_methodMocker.MockMethodReturnMap<string, int, bool, DateTime, double, char, string>(
typeof(ComplexService),
"ProcessComplexMapping",
complexMap
);
// Mock property getter
_methodMocker.MockPropertyGetter<bool>(
typeof(User),
"IsAdmin",
() => true
);
// Mock async method that returns Task<TResult>
_methodMocker.MockAsyncMethodReturn<string>(
typeof(DataService),
"GetDataAsync", // public async Task<string> GetDataAsync()
async () => {
// Real async logic can be performed here
await Task.Delay(10);
return "Mocked async data"; // Returns string, method returns Task<string>
}
);
// Mock async method with parameters that returns Task<TResult>
_methodMocker.MockAsyncMethodReturn<int, string>(
typeof(OrderService),
"ProcessOrderAsync", // public async Task<string> ProcessOrderAsync(int orderId)
async (orderId) => {
await Task.Delay(5);
return $"Processed order {orderId}"; // Returns string, method returns Task<string>
}
);
// Mock async method that returns Task (no result - void async)
// Single parameter
_methodMocker.MockAsyncMethod<string>(
typeof(AsyncService),
"ProcessDataAsync", // public async Task ProcessDataAsync(string data)
async (data) => {
// Simulate async operation
await Task.Delay(10);
Console.WriteLine($"Async processing: {data}");
// No return value - method returns Task
}
);
// Mock async Task method with two parameters
_methodMocker.MockAsyncMethod<string, int>(
typeof(AsyncService),
"ProcessDataWithCountAsync", // public async Task ProcessDataWithCountAsync(string data, int count)
async (data, count) => {
await Task.Delay(10);
Console.WriteLine($"Processing {data} with count {count}");
}
);
// Mock async Task method with three parameters
_methodMocker.MockAsyncMethod<string, int, bool>(
typeof(AsyncService),
"ProcessUserAsync", // public async Task ProcessUserAsync(string name, int age, bool isActive)
async (name, age, isActive) => {
await Task.Delay(10);
Console.WriteLine($"Processing user: {name}, {age}, {isActive}");
}
);
// Mock async Task method with four parameters
_methodMocker.MockAsyncMethod<string, int, bool, DateTime>(
typeof(AsyncService),
"ProcessComplexDataAsync", // public async Task ProcessComplexDataAsync(string name, int count, bool flag, DateTime date)
async (name, count, flag, date) => {
await Task.Delay(10);
Console.WriteLine($"Processing complex data: {name}, {count}, {flag}, {date}");
}
);
// Mock async Task method with five parameters
_methodMocker.MockAsyncMethod<string, int, bool, DateTime, double>(
typeof(AsyncService),
"ProcessMaxParamsAsync", // public async Task ProcessMaxParamsAsync(string name, int count, bool flag, DateTime date, double value)
async (name, count, flag, date, value) => {
await Task.Delay(10);
Console.WriteLine($"Processing max params: {name}, {count}, {flag}, {date}, {value}");
}
);
// Mock void method with parameters
_methodMocker.MockVoidMethod<string, int>(
typeof(DataProcessor),
"ProcessData",
(data, count) => {
// Capture parameters and execute custom logic
Console.WriteLine($"Processing {data} with count {count}");
}
);
// Mock extension methods (like SetReferenceType)
_methodMocker.MockVoidMethod<ICommunicationInternalManager, string>(
typeof(CommunicationExtensions),
"SetReferenceType",
(manager, referenceType) => {
// Mock the extension method behavior
Console.WriteLine($"SetReferenceType called with: {referenceType}");
}
);
// Mock void method to throw exceptions
_methodMocker.MockVoidMethod<string>(
typeof(FileService),
"DeleteFile",
(filePath) => {
throw new FileNotFoundException($"File not found: {filePath}");
}
);
// Mock async Task methods (void async methods)
_methodMocker.MockAsyncMethod<string>(
typeof(AsyncService),
"ProcessDataAsync",
async (data) => {
// Simulate async operation
await Task.Delay(10);
Console.WriteLine($"Async processing: {data}");
// Can also throw exceptions or perform other logic
}
);
// Define an extension method
public static class EnumExtensions
{
public static string GetEnumDisplayName(this Enum value)
{
return value.ToString();
}
}
public enum TestStatus
{
Active,
Inactive,
Pending,
Completed
}
// Mock the extension method
_methodMocker.MockMethodReturn<Enum, string>(
typeof(EnumExtensions),
"GetEnumDisplayName",
(enumValue) => $"Mocked-{enumValue}"
);
// Use the mocked extension method
var result = TestStatus.Active.GetEnumDisplayName();
// result = "Mocked-Active"
// Extension method parameter mapping
var enumDisplayMap = new Dictionary<Enum, string>
{
{ TestStatus.Active, "活跃" },
{ TestStatus.Inactive, "非活跃" },
{ TestStatus.Pending, "待处理" },
{ TestStatus.Completed, "已完成" }
};
_methodMocker.MockMethodReturnMap<Enum, string>(
typeof(EnumExtensions),
"GetEnumDisplayName",
enumDisplayMap
);
// Test different enum values
Assert.Equal("活跃", TestStatus.Active.GetEnumDisplayName());
Assert.Equal("非活跃", TestStatus.Inactive.GetEnumDisplayName());
// Extension method with complex logic
_methodMocker.MockMethodReturn<Enum, string>(
typeof(EnumExtensions),
"GetEnumDisplayName",
(enumValue) =>
{
return enumValue switch
{
TestStatus.Active => "🟢 Active",
TestStatus.Inactive => "🔴 Inactive",
TestStatus.Pending => "🟡 Pending",
TestStatus.Completed => "✅ Completed",
_ => "❓ Unknown"
};
}
);
// 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);
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>());
}
}
// 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}";
}
);
Dispose() after tests to release all mocksMockMethodReturnMap, undefined parameter combinations will throw KeyNotFoundExceptionawait in replacement functionsthis parameter typeMockAsyncMethod to mock methods that return Task (void async methods) - these support real async operations with awaitusing 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);
}
}
using System;
using Xunit;
using SimplyMock;
public interface ICommunicationManager
{
// Interface definition
}
public class TestCommunicationManager : ICommunicationManager
{
// Implementation
}
public static class CommunicationExtensions
{
public static void SetReferenceType(this ICommunicationManager manager, string referenceType)
{
// Original extension method implementation
Console.WriteLine($"Original SetReferenceType: {referenceType}");
}
}
public class VoidMethodTests : IDisposable
{
private readonly IMethodMocker _methodMocker;
public VoidMethodTests()
{
_methodMocker = new MethodMocker();
}
public void Dispose()
{
_methodMocker.Dispose();
}
[Fact]
public void SetReferenceType_ShouldBeMocked()
{
// Arrange - Mock the extension method
string capturedReferenceType = null;
ICommunicationManager capturedManager = null;
_methodMocker.MockVoidMethod<ICommunicationManager, string>(
typeof(CommunicationExtensions),
nameof(CommunicationExtensions.SetReferenceType),
(manager, referenceType) =>
{
capturedManager = manager;
capturedReferenceType = referenceType;
Console.WriteLine($"Mocked SetReferenceType: {referenceType}");
});
var manager = new TestCommunicationManager();
// Act - Call the mocked extension method
manager.SetReferenceType("TestReference");
// Assert - Verify the mock was called
Assert.Same(manager, capturedManager);
Assert.Equal("TestReference", capturedReferenceType);
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
Version 1.5.1:
change Lib.Harmony nuget Version to 2.3.6:
Version 1.5.0:
- Extended parameter support: All mock methods now support up to 10 parameters (previously 5)
- Added MockMethodReturn, MockMethodReturnMap, MockVoidMethod, MockAsyncMethodReturn, and MockAsyncMethod overloads for 6-10 parameters
- Modular architecture with partial classes for better maintainability
- 100% backward compatible - no breaking changes
- Comprehensive test coverage with 27 new test cases