devlooped/moq · error · NotSupportedException

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 can only generate runtime proxies for interfaces, delegates, or non-sealed, non-static classes. This NotSupportedException is thrown when Type/Mock<T> is given a type that violates these constraints (sealed class, static class, or otherwise unmockable type).

Solutions

  1. Mock the interface the sealed class implements (e.g. Mock<IFileService> instead of Mock<FileService>).
  2. Extract an interface or make the class methods virtual and unseal the class if you own it.
  3. Use a wrapper/adapter (e.g. SystemWrapper-style) around the unmockable type and mock the wrapper.
  4. For delegates, ensure the type actually is a delegate type; sealed static behavior can be faked by abstracting it away.

Example fix

// before
var mock = new Mock<FileService>(); // FileService is sealed
// after
IFileService svc = mock.Setup(m => m.Read()).Returns("data").Object;
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureMockable(Type t)
{
    var ti = t.GetTypeInfo();
    if (t.IsSealed && !ti.IsDelegate()) throw new InvalidOperationException($"{t.Name} is sealed/static; mock an interface instead");
}

Type guard

static bool IsMockable(Type t) =>
    t.IsInterface || t.IsSubclassOf(typeof(Delegate)) ||
    (!t.IsSealed && !t.IsStatic());

Try / catch

try { var mock = new Mock<T>(); }
catch (NotSupportedException ex) when (ex.Message.Contains("must be an interface"))
{
    // switch to mocking the interface implemented by T
}

Prevention

When it happens

Trigger: new Mock<SomeSealedClass>(); mock.Create() on a static class; Mock.Of<T>() with a sealed struct or sealed type; passing a sealed dependency class instead of its interface into MockRepository/fixture auto-mocking.

Common situations: Mocking a sealed third-party class; trying to mock DateTime/string/other special types; attempting to mock a static class for its members; after a type was made sealed during refactoring.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16). Data as JSON: /api/errors/bbca9adc803769d6. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/Guard.cs:212

            {
                throw new ArgumentException(Resources.ArgumentCannotBeEmpty, paramName);
            }
        }

        public static void NotField(MemberExpression memberAccess)
        {
            if (memberAccess.Member is FieldInfo)
                throw new NotSupportedException(
                    string.Format(
                        Resources.FieldsNotSupported,
                        memberAccess.ToStringFixed()));
        }

        public static void IsMockable(Type type)
        {
            if (!type.IsMockable())
            {
                throw new NotSupportedException(
                    string.Format(
                        Resources.TypeNotMockable,
                        type.GetFormattedName()));
            }
        }

        public static void Positive(TimeSpan delay)
        {
            if (delay <= TimeSpan.Zero)
            {
                throw new ArgumentException(Resources.DelaysMustBeGreaterThanZero);
            }
        }

        public static void CanRead(PropertyInfo property)
        {
            if (!property.CanRead(out _))
            {

View on GitHub (pinned to 89a5be629c)