devlooped/moq · error · ArgumentException
Method . is public. Use strong-typed Expect overload…
Error message
Method {0}.{1} is public. Use strong-typed Expect overload instead:
mock.Setup(x => x.{1}());
What it means
ProtectedMock's InternalSetup/InternalSetupSequence/InternalVerify guard against accidentally using the Protected API for a public method. If the resolved member is public, ThrowIfPublicMethod throws ArgumentException with Resources.MethodIsPublic telling you to use the strong-typed Expect overload: mock.Setup(x => x.Method()). The Protected API is strictly for non-public members.
Solutions
- Use the strong-typed API: mock.Setup(x => x.Method()) / mock.Verify(x => x.Method())
- If you truly need protected semantics, confirm the method is still non-public in the version you mock
- Pin/adjust for the library version — if the method became public, migrate the test to typed setups
Example fix
// before
mock.Protected().Setup("Save", ItExpr.IsAny<string>());
// after
mock.Setup(x => x.Save(It.IsAny<string>())); // Save is public Defensive patterns
Strategy: validation
Validate before calling
static bool IsProtected(Type t, string member) =>
t.GetMethod(member, BindingFlags.NonPublic | BindingFlags.Instance) is MethodInfo m && !m.IsPublic; Try / catch
try { mock.Protected().Setup("Save", ItExpr.IsAny<string>()); }
catch (ArgumentException ex) when (ex.Message.Contains("is public")) { /* switch to mock.Setup(x => x.Save(...)) */ } Prevention
- Check member accessibility with an IDE before using the Protected API
- After upgrading a mocked library, re-check members that became public
- Default to strong-typed Mock<T> setups for anything public
- Keep a convention: Protected() only for members declared protected/protected internal
When it happens
Trigger: mock.Protected().Setup("PublicMethod") or .As<TAnalog>() setups where the matched method on T is public (e.g. the method was made public in a newer version, or the wrong member-name string resolved to a public method).
Common situations: Library upgrade changed a method from protected to public; developer assumed the method was protected without checking; analog-type rewriting resolved to a public member.
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
- To specify a setup for public property
- ex.Message from ReplaceDuck expression rewriting (rethrown…
- ex.Message (re-thrown ArgumentException with paramName…
- Type does not have matching protected member
- Member . does not exist.
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/8d86f672d92d18c6.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Protected/ProtectedMock.cs:415
}
}
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.MethodMissing,
typeof(T).Name,
methodName,
string.Join(
", ",
extractedTypeNames.ToArray())));
}
}
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));
}
}View on GitHub (pinned to 89a5be629c)