有没有可能嘲弄这句话;键入名称";在C#中使用Moq进行模拟?

有没有可能嘲弄这句话;键入名称";在C#中使用Moq进行模拟?,c#,testing,mocking,moq,C#,Testing,Mocking,Moq,我正在用C#(基于.NET内核)开发一个具有模块化行为的聊天机器人。我想开发的行为之一是“管理”模块,该模块(除其他功能外)应允许管理员按名称动态启用或禁用其他行为 我希望管理模块通过检查行为的类型信息并执行以下操作来确定行为的名称: var name = behaviour.GetType().GetTypeInfo().Name.Replace("Behaviour", string.Empty).ToLowerInvariant(); 在我首先编写的BDD规范中,我试图建立一个“行为链”

我正在用C#(基于.NET内核)开发一个具有模块化行为的聊天机器人。我想开发的行为之一是“管理”模块,该模块(除其他功能外)应允许管理员按名称动态启用或禁用其他行为

我希望管理模块通过检查行为的类型信息并执行以下操作来确定行为的名称:

var name = behaviour.GetType().GetTypeInfo().Name.Replace("Behaviour", string.Empty).ToLowerInvariant();
在我首先编写的BDD规范中,我试图建立一个“行为链”,由管理模块(测试中的系统)和模拟行为组成。这些测试包括发送命令,这些命令应该会导致管理模块启用或禁用模拟行为

这就是我到目前为止所做的:

public BehaviourIsEnabled() : base("Admin requests that a behaviour is enabled")
{
    var mockTypeInfo = new Mock<TypeInfo>();
    mockTypeInfo.SetupGet(it => it.Name).Returns("MockBehaviour");

    var mockType = new Mock<Type>();
    mockType.Setup(it => it.GetTypeInfo()).Returns(mockTypeInfo.Object);

    // TODO: make mock behaviour respond to "foo"
    var mockBehaviour = new Mock<IMofichanBehaviour>();
    mockBehaviour.Setup(b => b.GetType()).Returns(mockType.Object);

    this.Given(s => s.Given_Mofichan_is_configured_with_behaviour("administration"), AddBehaviourTemplate)
        .Given(s => s.Given_Mofichan_is_configured_with_behaviour(mockBehaviour.Object),
                "Given Mofichan is configured with a mock behaviour")
            .And(s => s.Given_Mofichan_is_running())
        .When(s => s.When_I_request_that_a_behaviour_is_enabled("mock"))
            .And(s => s.When_Mofichan_receives_a_message(this.JohnSmithUser, "foo"))
        .Then(s => s.Then_the_mock_behaviour_should_have_been_triggered())
        .TearDownWith(s => s.TearDown());
}
public behaviousEnabled():base(“管理员请求启用行为”)
{
var mockTypeInfo=new Mock();
mockTypeInfo.SetupGet(it=>it.Name).Returns(“mockbehavior”);
var mockType=new Mock();
mockType.Setup(it=>it.GetTypeInfo()).Returns(mockTypeInfo.Object);
//TODO:使模拟行为响应“foo”
var mockbehavior=new Mock();
mockBehavior.Setup(b=>b.GetType()).Returns(mockType.Object);
此.Given(s=>s.Given_Mofichan_配置了_行为(“管理”),addBehavior模板)
.Given(s=>s.Given_Mofichan_配置了_行为(mockbehavior.Object),
“给定Mofichan配置了模拟行为”)
和(s=>s.给定的\u Mofichan\u正在运行()
.When(s=>s.When\I\u请求\u行为\u已启用(“模拟”))
和(s=>s.当Mofichan收到消息时(this.JohnSmithUser,“foo”))
.然后(s=>s.然后\u模拟行为\u应该\u被触发()
.TearDownWith(s=>s.TearDown());
}
运行此命令时的问题是
GetTypeInfo()
Type
上的扩展方法,因此Moq抛出异常:

表达式引用不属于模拟对象的方法 对象:it=>it.GetTypeInfo()


另一种选择是,我可以在
imofichanbehavior
中添加
Name
属性,但我不喜欢在生产代码中添加任意方法/属性的想法,这只是为了测试代码的好处。

使用满足所模拟内容的伪类保持简单

public class MockBehaviour : IMofichanBehaviour { ... }
然后这个测试看起来像

public BehaviourIsEnabled() : base("Admin requests that a behaviour is enabled") {

    // TODO: make mock behaviour respond to "foo"
    var mockBehaviour = new MockBehaviour();


    this.Given(s => s.Given_Mofichan_is_configured_with_behaviour("administration"), AddBehaviourTemplate)
        .Given(s => s.Given_Mofichan_is_configured_with_behaviour(mockBehaviour),
                "Given Mofichan is configured with a mock behaviour")
            .And(s => s.Given_Mofichan_is_running())
        .When(s => s.When_I_request_that_a_behaviour_is_enabled("mock"))
            .And(s => s.When_Mofichan_receives_a_message(this.JohnSmithUser, "foo"))
        .Then(s => s.Then_the_mock_behaviour_should_have_been_triggered())
        .TearDownWith(s => s.TearDown());
}

显示扩展方法。扩展方法(静态)使测试变得困难,这取决于方法的复杂性,也取决于一个事实,即为了可测试性,应该尽量避免使用静态类和方法。@Nkosi显示扩展方法是什么意思?我在帖子里写的:。您是对的,最好避免使用扩展/静态方法,但在这种情况下,我没有太多选择,因为它是一个内置的方法,我必须使用它来检查.NET Core中的类型信息。然后使用一个伪方法,即:
公共类mockbehavior:imofichanbehavior{…}
+1,这很简单但有效。我很高兴我自己没有想到这件事。我之前考虑过“Name/Id”的概念,实际上我已经走上了这条路,但如果我再次需要这种行为,这是一个很好的方法。也可以接受,除非有人发布一种在Moq中模拟类型信息的方法,这会稍微方便一些,但决不是必需的。