Moq
mocking
generic methods
C#
unit testing

Mocking generic methods in Moq without specifying T

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Mocking generic methods in C# with Moq becomes difficult when you do not know the type parameter T at compile time. Moq's Setup requires a concrete type for generic parameters, so mock.Setup(x => x.Get<T>(...)) does not compile when T is unknown. The workaround depends on your scenario: if you know the finite set of types, set up each one explicitly. If the type is truly open, use reflection to invoke Setup dynamically, or redesign the interface to avoid open generics. This article covers all approaches with working examples.

The Problem

csharp
1public interface IRepository
2{
3    T Get<T>(int id) where T : class;
4    void Save<T>(T entity) where T : class;
5}
6
7// This does NOT compile — T is not a concrete type
8mock.Setup(x => x.Get<T>(It.IsAny<int>())).Returns(default(T));

Moq uses expression trees internally, and expression trees require concrete types at compile time. You cannot pass an open generic parameter to Setup.

Fix 1: Set Up Each Known Type Explicitly

csharp
1var mock = new Mock<IRepository>();
2
3// Set up for each type you expect the code under test to use
4mock.Setup(x => x.Get<User>(It.IsAny<int>()))
5    .Returns(new User { Id = 1, Name = "Alice" });
6
7mock.Setup(x => x.Get<Order>(It.IsAny<int>()))
8    .Returns(new Order { Id = 1, Total = 99.99m });
9
10mock.Setup(x => x.Get<Product>(It.IsAny<int>()))
11    .Returns(new Product { Id = 1, Name = "Widget" });
12
13var service = new MyService(mock.Object);
14service.Process();  // Calls Get<User>, Get<Order>, etc.

This is the simplest and most readable approach. In most unit tests, you know exactly which types the code under test will request.

Fix 2: Helper Method with Generic Constraint

csharp
1private Mock<IRepository> SetupRepository()
2{
3    var mock = new Mock<IRepository>();
4    SetupGet<User>(mock, new User { Id = 1, Name = "Alice" });
5    SetupGet<Order>(mock, new Order { Id = 1, Total = 50m });
6    return mock;
7}
8
9private void SetupGet<T>(Mock<IRepository> mock, T result) where T : class
10{
11    mock.Setup(x => x.Get<T>(It.IsAny<int>())).Returns(result);
12}

A generic helper method reduces repetition when you need to set up many types with the same pattern.

Fix 3: Reflection for Truly Open Generics

csharp
1using System.Reflection;
2
3public static void SetupGenericGet(Mock<IRepository> mock, Type entityType, object result)
4{
5    // Get the Setup method on Mock<IRepository>
6    var mockType = mock.GetType();
7
8    // Build the expression manually
9    var parameter = Expression.Parameter(typeof(IRepository), "x");
10    var method = typeof(IRepository).GetMethod("Get").MakeGenericMethod(entityType);
11    var call = Expression.Call(parameter, method, Expression.Constant(0));
12
13    // This approach is complex — consider alternatives first
14}
15
16// Simpler: use mock.As<>() or a callback dictionary
17var mock = new Mock<IRepository>();
18var store = new Dictionary<(Type, int), object>
19{
20    { (typeof(User), 1), new User { Id = 1, Name = "Alice" } },
21    { (typeof(Order), 1), new Order { Id = 1, Total = 50m } },
22};
23
24// Set up each registered type
25foreach (var group in store.GroupBy(x => x.Key.Item1))
26{
27    // Still need per-type setup — reflection adds complexity without much benefit
28}

Reflection-based approaches are fragile and hard to maintain. In practice, the explicit per-type setup is almost always better.

Fix 4: Redesign the Interface

csharp
1// Instead of a generic method:
2public interface IRepository
3{
4    T Get<T>(int id) where T : class;
5}
6
7// Use a non-generic base with typed implementations:
8public interface IRepository<T> where T : class
9{
10    T Get(int id);
11}
12
13// Now mocking is straightforward
14var userRepo = new Mock<IRepository<User>>();
15userRepo.Setup(x => x.Get(It.IsAny<int>()))
16    .Returns(new User { Id = 1, Name = "Alice" });

If you control the interface, making it generic at the interface level (not method level) sidesteps the problem entirely. Each mock targets a specific T.

Fix 5: Using Moq Callbacks as a Workaround

csharp
1var mock = new Mock<IRepository>();
2
3// Set up with a callback that uses a dictionary
4mock.Setup(x => x.Get<User>(It.IsAny<int>()))
5    .Returns((int id) =>
6    {
7        var users = new Dictionary<int, User>
8        {
9            { 1, new User { Id = 1, Name = "Alice" } },
10            { 2, new User { Id = 2, Name = "Bob" } }
11        };
12        return users.GetValueOrDefault(id);
13    });

Callbacks give you runtime control over the return value while keeping the setup type-safe and readable.

Verifying Generic Method Calls

csharp
1var mock = new Mock<IRepository>();
2
3mock.Setup(x => x.Save(It.IsAny<User>()));
4
5var service = new MyService(mock.Object);
6service.CreateUser("Alice");
7
8// Verify the generic method was called with expected arguments
9mock.Verify(x => x.Save(It.Is<User>(u => u.Name == "Alice")), Times.Once);
10
11// Verify any call to Save<User>
12mock.Verify(x => x.Save(It.IsAny<User>()), Times.Once);

Common Pitfalls

  • Trying to use an open generic in Setup: mock.Setup(x => x.Get<T>(...)) where T is a type parameter does not compile. You must supply a concrete type like Get<User>.
  • Forgetting to set up all used types: If the code under test calls Get<Order> but you only set up Get<User>, Moq returns default(Order) (null for reference types), which may cause NullReferenceException downstream.
  • Over-engineering with reflection: Reflection-based generic setups are brittle, hard to debug, and rarely necessary. Prefer explicit setups for each concrete type.
  • Not verifying the type parameter: mock.Verify(x => x.Save(It.IsAny<User>())) only verifies calls with T = User. A call to Save<Order> does not match, which may hide bugs.
  • Ignoring interface redesign: If you find yourself needing open-generic mocks frequently, the interface design may be the real problem. Generic interfaces (IRepository<T>) are easier to mock than generic methods.

Summary

  • Moq requires concrete types for generic method setups — open T does not compile
  • The simplest fix is setting up each known type explicitly (Get<User>, Get<Order>, etc.)
  • Use a generic helper method to reduce boilerplate when setting up many types
  • Reflection-based approaches work but are fragile and rarely worth the complexity
  • Redesigning the interface from generic methods to generic interfaces makes mocking straightforward
  • Always verify generic method calls with the correct type parameter to catch bugs

Course illustration
Course illustration

All Rights Reserved.