devlooped/moq · error · ArgumentException

To specify a setup for public property

Error message

To specify a setup for public property {0}.{1}, use the typed overloads, such as:
mock.Setup(x => x.{1}).Returns(value);
mock.SetupGet(x => x.{1}).Returns(value); //equivalent to previous one
mock.SetupSet(x => x.{1}).Callback(callbackDelegate);

What it means

SetupGet/Setup-family APIs for protected members call ThrowIfPublicGetter to reject properties whose getter is public on the mocked type, throwing ArgumentException with Resources.UnexpectedPublicProperty that lists the typed-overload alternatives (Setup, SetupGet, SetupSet with lambdas). The Protected API must only be used for non-public property getters.

Solutions

  1. Use the strong-typed mock.Setup(x => x.Prop).Returns(v) or mock.SetupGet(x => x.Prop).Returns(v)
  2. If only the getter is public but setter is protected, keep using Protected().SetupSet for the setter path
  3. Update tests after accessibility changes in a library upgrade

Example fix

// before
mock.Protected().Setup<string>("Name");
// after
mock.SetupGet(x => x.Name).Returns("abc"); // Name getter is public
Defensive patterns

Strategy: validation

Validate before calling

static bool GetterIsProtected(Type t, string prop) =>
    t.GetProperty(prop, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) is { } p
    && p.GetGetMethod(true) is { } g && !g.IsPublic;

Try / catch

try { mock.Protected().Setup<string>("Name"); }
catch (ArgumentException ex) when (ex.Message.Contains("public property")) { /* use mock.SetupGet(x => x.Name) */ }

Prevention

When it happens

Trigger: mock.Protected().Setup<string>("PublicProp") or SetupGet("PublicProp") where T.PublicProp has a public getter — common after the property's accessibility changed to public.

Common situations: Property was protected in an older library version and became public; developer assumed non-public; Setup used for a getter-style property that is actually public.

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


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

Appendix: source

Thrown at src/Moq/Protected/ProtectedMock.cs:427

        }

        static void ThrowIfPublicMethod(MethodInfo method, string reflectedTypeName)
        {
            if (method.IsPublic)
            {
                throw new ArgumentException(string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.MethodIsPublic,
                    reflectedTypeName,
                    method.Name));
            }
        }

        static void ThrowIfPublicGetter(PropertyInfo property, string reflectedTypeName)
        {
            if (property.CanRead(out var getter) && getter.IsPublic)
            {
                throw new ArgumentException(string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.UnexpectedPublicProperty,
                    reflectedTypeName,
                    property.Name));
            }
        }

        static void ThrowIfPublicSetter(PropertyInfo property, string reflectedTypeName)
        {
            if (property.CanWrite(out var setter) && setter.IsPublic)
            {
                throw new ArgumentException(string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.UnexpectedPublicProperty,
                    reflectedTypeName,
                    property.Name));
            }
        }

View on GitHub (pinned to 89a5be629c)