2011-04-05 104 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