Could we add Verify methods to IMock<T>?
ignoring the opinion we shouldn't verify loggers...we do... ILogger<X> implements ILogger and IMock<ILogger<X>> can be cast to IMock<ILogger> since T is covariant in IMock<T> but the helper extension methods we have for IMock<ILogger> use Verify methods...which are not on IMock<T> just Mock<T>.
As such we've had to dupe all our helper methods one set for Mock<ILogger> and a 2nd for Mock<ILogger<T>> which i mean...who cares but wondering if we can go a little DRYer in the implementation.
So wondering if there's a reason the Verify methods aren't on IMock<T>
initial glance all the Verify signatures look ok for IMock, but since this wasn't done i'm guessing there was a reason...but i didn't stumble upon it with an hour of searching so either i suck at searching or it's not mentioned as to why it was skipped or i'm really the first to consider it (most unlikely).
If it's about other implementations of IMock not wanted to support verify would u consider an IVerifiableMock<T> in the hierarchy, or would that be too much to maintain. totally get that.
looking forward to insights, thanks!
I can't recall a good reason either right now 🤔
Due to lack of recent activity, this issue has been labeled as 'stale'. It will be closed if no further activity occurs within 30 more days. Any new comment will remove the label.
still interested
This is what copilot on the repo had to say:
Short answer: Because IMock<T> is intentionally covariant and Verify consumes T.
Details:
- IMock<T> is declared covariant (out T) and “only covers the covariant members of Mock<T>.” See the comment in IMock.cs. This design lets an IMock<Derived> be used where an IMock<Base> is expected, but it also means the interface cannot expose members that take T in input position (contravariant), such as Verify signatures that accept Expression<Action<T>> or Expression<Func<T, TResult>>.
- IMock<T>: src/Moq/IMock.cs
- The Verify APIs are implemented as instance methods on Mock<T> (not on the interface) and they all take expressions that consume T:
- Example: Verify<TResult>(Expression<Func<T, TResult>> expression, Times times): src/Moq/Mock`1.cs#L810-L823
- The older property verification overloads were moved into “obsolete” extension methods specifically “as they confuse the compiler with the overloads taking Action,” and these extend Mock<T>, not IMock<T>:
- Note in ObsoleteMockExtensions: src/Moq/Obsolete/ObsoleteMockExtensions.cs#L66-L75
Would it be trivial to move Verify to IMock<T>?
- Not really. To put Verify on IMock<T> proper, you’d have to drop covariance (remove out T) or add contravariant members to a covariant interface, which isn’t allowed and would be a breaking change.
- You could add new extension methods declared on IMock<T> that forward to the underlying Mock<T> (e.g., via Mock.Get(mock.Object)). That’s technically possible but:
- It relies on the object being a Moq-generated proxy (IMocked) and thus on implementation details.
- It risks reintroducing overload resolution ambiguities that the library intentionally avoided by pushing certain overloads into obsolete extensions on Mock<T>.
- It doesn’t align with the stated intent of IMock<T>, which is a narrow covariant surface for passing around mocks, while the full authoring API (setup/verify) lives on Mock<T>.
So the current design is deliberate: IMock<T> stays covariant and minimal; Verify remains on Mock<T>.
Note: The code search results shown here may be incomplete. You can continue browsing in GitHub:
- Repo code search for “IMock”: https://github.com/devlooped/moq/search?q=IMock&type=code
- Repo code search for “Verify”: https://github.com/devlooped/moq/search?q=Verify&type=code
