2011-04-05 127 views
1

我有一個服務負責訂閱EWS以獲取新的郵件通知。我爲服務創建了一個接口來模擬它並測試一個虛擬實現。然而,每當我嘗試手動告訴我的事件應該做什麼時,我都會碰壁。如何使用內部構造函數模擬事件

這是我的具體實現。

public interface IExchangeService 
{ 
    void Subscribe(); 
} 

public class ExchangeServiceSubscriber : IExchangeService 
{ 
    private readonly ExchangeService _exchangeService; 
    private readonly IConsumer<IEmail> _consumer; 

    public ExchangeServiceSubscriber(
     ExchangeService exchangeService, 
     IConsumer<IEmail> consumer) 
    { 
     _exchangeService = exchangeService; 
     _consumer = consumer; 
    } 

    public void Subscribe() 
    { 
     // code to subscribe 

     streamingConnection.OnNotificationEvent += OnEvent; 

     streamingConnection.Open(); 
    } 

    public void OnEvent(object sender, NotificationEventArgs args) 
    { 
     foreach (NotificationEvent triggeredEvent in args.Events) 
     { 
      if (triggeredEvent is ItemEvent) 
      { 
       var propertySet = new PropertySet(ItemSchema.UniqueBody, ItemSchema.Attachments) 
       { 
        RequestedBodyType = BodyType.Text 
       }; 
       EmailMessage email = EmailMessage.Bind(args.Subscription.Service, 
                 ((ItemEvent)triggeredEvent).ItemId, propertySet); 

       _consumer.Consume(new ExchangeEmail { Body = email.UniqueBody }); 
      } 
     } 
    } 
} 

而且不幸的是,幾乎在每一個EWS類要麼密封或具有真正限制我如何去耦,似乎內部構造。我試圖設置NotificationEventArgs(例如)的期望值,但它使用了一個內部構造函數。

這是我一直在擺弄的一些想法。你可以閱讀關於嘲笑事件here

mock.Setup(x => x.OnEvent(new object(), new NotificationEventArgs())); 問題是NotificationEventArgs使用內部構造函數。

我可以看到使用某種封裝工作,但我不完全確定它會是什麼樣子。其中一個重大問題是EWS幾乎無法防止任何人手動注入依賴關係。我基本上試圖測試,無論何時事件OnEvent引發電子郵件實際上將被消耗。另外,雖然我想測試這個功能,但我不確定值得與EWS的每一步戰鬥。

+0

你什麼時候寫的'inline'你的意思'internal'?代碼示例中使用'SubscriptionErrorEventArgs'的位置在哪裏? – 2011-04-05 16:39:47

+0

是的,你是對的。我的意思是「內部」。我的意思是寫'NotificationEventArgs'而不是'SubscriptionErrorEventArgs'。請參閱編輯。 – Mike 2011-04-05 16:42:26

+0

您能否請您展示您當前不使用的方法?原因:我不知道最小起訂量,但是你的方法仍然可以讓我想出一些想法。 – 2011-04-05 16:46:01

回答

3

讓我們先來看看,你不能做什麼:

  • 不能繼承NotificationEventArgs因爲構造函數是內部的。
  • 由於相同的原因,您不能直接創建實例。

所以基本上,你不能使用「普通方式」創建這個類的實例。我假設你已經檢查過工廠方法或類嗎?

這讓我們只有一個選擇:使用反射實例化類,例如,與Activator.CreateInstance方法的幫助:Unit testing exception handling for third party exceptions with internal constructors,就像這樣:

mock.Setup(x => x.OnEvent(new object(), 
      Activator.CreateInstance(typeof(NotificationEventArgs), 
           BindingFlags.NonPublic | BindingFlags.Instance, 
           null, 
           null, 
           null)) 
      ); 
+0

不是一個壞主意。讓我看看我能做些什麼。 – Mike 2011-04-05 17:16:17

+0

我不認爲這種方法可行。我目前正在開發一個事件包裝器實現,它會*嘗試*模擬手動引發模擬的通知事件。 – Mike 2011-04-06 15:41:37

+0

我不明白。對於你的例子,它會像這樣工作:'mock.Setup(x => x.OnEvent(new object(),Activator.CreateInstance(typeof(NotificationEventArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, null , null)));' – 2011-04-06 15:43:14