devlooped/moq · error · ArgumentException
Type to mock ( ) must be an interface, a delegate, or a…
Error message
Type to mock ({0}) must be an interface, a delegate, or a non-sealed, non-static class. What it means
Moq creates mock objects by generating a dynamic proxy via Castle DynamicProxy in CastleProxyFactory.CreateProxy. When the proxy generator fails with a TypeLoadException, Moq rethrows it as an ArgumentException using the TypeNotMockable resource: the target type must be an interface, a delegate, or a non-sealed, non-static class. Sealed classes, static classes, and types with inaccessible internals cannot be proxied.
Solutions
- Mock the interface the class implements instead of the sealed class itself.
- Remove 'sealed' from the class (and make mocked members public virtual) if you own the code.
- For internal types, add [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] to the mocked assembly.
- Wrap the unmockable dependency behind your own interface for testability.
Example fix
// before var mock = new Mock<string>(); // string is sealed // after var mock = new Mock<IMessageBuilder>(); // mock the interface instead
Defensive patterns
Strategy: validation
Validate before calling
static bool IsMockable(Type t) =>
t.IsInterface || t.IsSubclassOf(typeof(Delegate)) ||
(!t.IsSealed && !t.IsStatic() && !t.IsAbstractWithNoCtorAccessible());
// simplest safe check:
// if (type.IsSealed || type.IsAbstract) throw new InvalidOperationException($"{type.Name} cannot be mocked; mock an interface instead."); Type guard
static bool CanMock(Type t) => t.IsInterface || (!t.IsSealed && !t.IsAbstract || t.IsSubclassOf(typeof(Delegate)));
Try / catch
try { var mock = new Mock<T>(); }
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { /* fall back to interface mock or manual fake */ } Prevention
- Design dependencies as interfaces so tests never mock concrete classes.
- Never mark classes you intend to mock as sealed or static.
- Make mocked members public virtual.
- Add InternalsVisibleTo("DynamicProxyGenAssembly2") if mocking internal types.
When it happens
Trigger: Calling Mock.Of<T>() or new Mock<T>() where T is a sealed class (e.g. string or a sealed DTO), a static class, or a non-public/inaccessible class whose methods Castle cannot override; CreateProxy catches TypeLoadException and throws this ArgumentException.
Common situations: Attempting to mock types from the BCL like string, HttpClient (partially), or framework sealed types; mocking third-party classes that were made sealed in a newer library version; trying to mock internal classes without InternalsVisibleTo("DynamicProxyGenAssembly2").
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Type to mock ( ) must be an interface, a delegate, or a…
- A matching constructor for the given arguments was not…
- It is impossible to call the provided strongly-typed…
- The equals ("==" or "=" in VB) and the conditional 'and'…
- LINQ method ' ' not supported.
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/d6e335f35c8c9151.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Interception/CastleProxyFactory.cs:74
// While `CreateClassProxy` could also be used for interface types,
// `CreateInterfaceProxyWithoutTarget` is much faster (about twice as fast):
return generator.CreateInterfaceProxyWithoutTarget(mockType, additionalInterfaces, this.generationOptions, new Interceptor(interceptor));
}
else if (mockType.IsDelegateType())
{
var options = new ProxyGenerationOptions();
options.AddDelegateTypeMixin(mockType);
var container = GetClassGenerator(mockType).CreateClassProxy(typeof(object), additionalInterfaces, options, new Interceptor(interceptor));
return Delegate.CreateDelegate(mockType, container, container.GetType().GetMethod("Invoke")!);
}
try
{
return GetClassGenerator(mockType).CreateClassProxy(mockType, additionalInterfaces, this.generationOptions, arguments, new Interceptor(interceptor));
}
catch (TypeLoadException e)
{
throw new ArgumentException(string.Format(Resources.TypeNotMockable, mockType), e);
}
catch (MissingMethodException e)
{
throw new ArgumentException(Resources.ConstructorNotFound, e);
}
}
public override bool IsMethodVisible(MethodInfo method, out string messageIfNotVisible)
{
return ProxyUtil.IsAccessible(method, out messageIfNotVisible);
}
public override bool IsTypeVisible(Type type)
{
return ProxyUtil.IsAccessible(type);
}
sealed class Interceptor : Castle.DynamicProxy.IInterceptorView on GitHub (pinned to 89a5be629c)