2016-11-13 95 views
1

我正在開發具有模塊化行爲的C#(基於.NET Core)的chatbot。我想開發的行爲之一是一個「管理」模塊(其他功能)應允許管理員通過名稱動態啓用或禁用其他行爲。是否有可能使用Moq在C#中模擬模擬的「類型名稱」?

我希望管理模塊通過檢查它的類型信息,並做這樣的事情來確定行爲的名稱:

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()); 
} 

的問題,當我跑這是GetTypeInfo()Type擴展方法,所以起訂量拋出該異常:

表達引用了一個不屬於嘲諷對象的方法:it => it.GetTypeInfo()

另一種方法是,我可以將Name屬性添加到IMofichanBehaviour,但我不喜歡爲生產代碼添加任意方法/屬性的想法,這只是爲了測試代碼的好處。

+0

顯示的擴展方法。擴展方法(靜態)會使事情難以測試,具體取決於方法的複雜性以及單純爲了可測試性而應該嘗試避免靜態類和方法的事實。 – Nkosi

+0

@Nkosi你是什麼意思顯示擴展方法?我在文章中給出了它:['GetTypeInfo()'](https://msdn.microsoft.com/en-us/library/system.reflection.introspectionextensions.gettypeinfo(v = vs.110).aspx) 。你是對的,擴展/靜態方法是最好的避免,但在這種情況下,我沒有太多的選擇,因爲它是一個內置的,我必須用來檢查.NET核心中的類型信息。 – Tagc

+1

然後使用一個假的:即公共類MockBehaviour:IMofichanBehaviour { – Nkosi

回答

1

保持簡單,假的類可以滿足它被嘲笑的地方。然後

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()); 
} 
+0

+1,這很簡單但有效。我面臨着自己沒有想到的問題。我之前正在研究「Name/Id」的想法,並且實際上已經沿着這條路線走下去了,但如果我再次需要這種行爲,這是一個很好的方法。除非有人發表了一種方式來模擬Moq中的類型信息,這也會被接受,這會稍微方便些,但絕非必要。 – Tagc