You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何Mock带有IEquatable<T>类型约束的泛型方法?

问题:Mock带泛型约束的泛型方法Push<T>

我在C#项目中使用xUnit和Moq4进行单元测试,需要Mock的接口如下:

public interface IEngine
{
    void Push<T>() where T : IEquatable<T>;
}

我希望按如下方式创建并设置该接口的Mock:

[Fact]
public void My_test()
{
   var value = 0;

   var mock = new Mock<IEngine>();

   mock.Setup(m => m.Push<???>()).Callback(() => value++);

   mock.Object.Push<TypeOne>();
   mock.Object.Push<TypeTwo>();

   Assert.Equal(2, value);
}

其中TypeOne和TypeTwo的定义为:

public class TypeOne : IEquatable<TypeOne>
{
    public bool Equals(TypeOne? other) => true;
}

public class TypeTwo : IEquatable<TypeTwo>
{
    public bool Equals(TypeTwo? other) => true;
}

我应该用什么替换代码中的???来让测试编译并正常运行?这是否可行?

我曾尝试如下写法:

mock.Setup(m => m.Push<IEquatable<It.IsAnyType>>()).Callback(() => value++);

但编译报错,错误信息为:

The type 'System.Equatable<Moq.It.IsAnyType>' cannot be used as type parameter 'T' in the generic type or method 'IEngine.Push()'. There is no implicit reference conversion from 'System.Equatable<Moq.It.IsAnyType>' to 'System.Equatable<System.Equatable<Moq.It.IsAnyType>>'.

我了解过Moq4中的ITypeMatcher接口和TypeMatcherAttribute,但不知道如何在该场景中应用,恳请帮助。


解决方案

要Mock所有符合IEquatable<T>约束的泛型Push<T>调用,可使用Moq的It.IsAnyType结合泛型约束匹配,具体写法如下:

mock.Setup(m => m.Push<It.IsAnyType>())
    .Where(T => typeof(IEquatable<>).MakeGenericType(T).IsAssignableFrom(T))
    .Callback(() => value++);

说明:

  • It.IsAnyType用于匹配任意泛型类型参数
  • .Where(T => ...)是Moq提供的泛型约束匹配方法,这里检查类型T是否实现了IEquatable<T>(与IEngine.Push<T>的约束一致)
  • 配置完成后,所有符合约束的Push<T>调用都会触发Callback逻辑,TypeOne和TypeTwo的调用都会让value自增,最终断言会通过。

如果只需匹配特定类型,也可以直接指定:

// 匹配TypeOne的Push调用
mock.Setup(m => m.Push<TypeOne>()).Callback(() => value++);
// 匹配TypeTwo的Push调用
mock.Setup(m => m.Push<TypeTwo>()).Callback(() => value++);

但如果需要批量匹配所有符合约束的类型,第一种方法更高效。


内容的提问来源于stack exchange,提问作者Dka8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 13:25:50