2010-02-04 49 views
1

我试图开发一个发送电子邮件的应用程序,而且我们的内部网络非常紧密,所以我无法使用我们的内部邮件服务器进行中继。测试SMTP的替代品?

有没有人曾经使用类似no-ip.com的东西?还有其他的选择吗?

+0

究竟是你想做些什么? – SLaks 2010-02-04 17:59:18

+0

用户提交表格,我们发送确认邮件。不是火箭科学。 – chris 2010-02-04 18:10:42

+0

编写您的PC上运行的自己的SMTP服务器。 – 2010-02-04 18:27:36

回答

4

如果你只需要t O检查电子邮件被发送到正确的地址,并用正确的内容,最简单的方法是通过编辑应用程序或web.config文件中使用投递文件夹:

<system.net> 
    <mailSettings> 
     <smtp deliveryMethod="SpecifiedPickupDirectory" from="[email protected]"> 
     <specifiedPickupDirectory pickupDirectoryLocation="C:\TestMailDrop"/> 
     </smtp> 
    </mailSettings> 
    </system.net> 

这将导致电子邮件被创建为指定目录中的文件。您甚至可以加载这些文件并将其作为单元测试的一部分进行验证。

(如codekaizen指出,这也可以在代码中完成,如果你不介意修改代码/硬编码投递文件夹,并具有行为在调试/释放模式有所不同。)

+0

+1以充分利用不良情况。 – 2010-02-04 18:26:09

+0

听起来像现在最好的选择 - 加上它显然是时候把我的简历上careers.stackoverflow.com :) – chris 2010-02-04 19:25:40

+0

我要限制自己的技术建议,而不是职业建议。但是,是的,如果你的雇主希望你做一些事情,然后阻止你做到这一点,你就会遇到问题。 – 2010-02-04 20:50:45

0

通常的答案是在IIS下本地运行SMTP,但您需要注意发送给谁。实际上,发送到通常的SMTP服务器并仅定位到您的域中的帐户可能会更好。

+0

不幸的是,甚至无法做到这一点。 – chris 2010-02-04 18:12:21

+0

哇。好的,那么技术爱好者的答案可能是最好的。 – 2010-02-04 18:23:50

2
+0

+1提供参考。 – 2010-02-04 18:11:43

2

您可以将电子邮件保存到磁盘:

#if DEBUG 
smtpClient.PickupDirectoryLocation = "\\Path\\to\\save\\folder"; 
smtpClient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory; 
smtpClient.Send(msg); 
#endif 
+0

这可行,但我更喜欢app.config解决方案,因为它不依赖于调试或发布版本。 – 2010-02-04 20:29:39

+0

是的,这是更好的方法......我刚刚忘了如何做配置技巧。 – codekaizen 2010-02-04 21:37:23

+1

+1你不想在配置文件中使用硬连线路径,否则它将成为维护的噩梦。您应该创建一个临时目录夹具,在测试之后将其擦除并针对其内容进行声明 – 2012-08-10 11:22:05

1

从@ Riffing codekaizen,使用AutoFixture.xUnit [其可作为一个包的xUnit该名称]: -

[Theory, AutoData] 
    public static void ShouldSendWithCorrectValues(string anonymousFrom, string anonymousRecipients, string anonymousSubject, string anonymousBody) 
    { 
     anonymousFrom += "@b.com"; 
     anonymousRecipients += "@c.com"; 

     using (var tempDir = new TemporaryDirectoryFixture()) 
     { 
      var capturingSmtpClient = new CapturingSmtpClientFixture(tempDir.DirectoryPath); 
      var sut = new EmailSender(capturingSmtpClient.SmtpClient); 

      sut.Send(anonymousFrom, anonymousRecipients, anonymousSubject, anonymousBody); 
      string expectedSingleFilename = capturingSmtpClient.EnumeratePickedUpFiles().Single(); 
      var result = File.ReadAllText(expectedSingleFilename); 

      Assert.Contains("From: " + anonymousFrom, result); 
      Assert.Contains("To: " + anonymousRecipients, result); 
      Assert.Contains("Subject: " + anonymousSubject, result); 
      Assert.Contains(anonymousBody, result); 
     } 
    } 

CapturingSmtpClientFixture仅在试验中使用的上下文

class CapturingSmtpClientFixture 
    { 
     readonly string _path; 
     readonly SmtpClient _smtpClient; 

     public CapturingSmtpClientFixture(string path) 
     { 
      _path = path; 
      _smtpClient = new SmtpClient { DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory, PickupDirectoryLocation = _path }; 
     } 

     public SmtpClient SmtpClient 
     { 
      get { return _smtpClient; } 
     } 

     public IEnumerable<string> EnumeratePickedUpFiles() 
     { 
      return Directory.EnumerateFiles(_path); 
     } 
    } 

然后,您需要做的就是确保您的实际代码提供的SmtpClient已经与适用于实时SMTP服务器的参数连接起来。

(为了完整起见,这里是TemporaryDirectoryFixture): -

public class TemporaryDirectoryFixture : IDisposable 
{ 
    readonly string _directoryPath; 

    public TemporaryDirectoryFixture() 
    { 
     string randomDirectoryName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); 

     _directoryPath = Path.Combine(Path.GetTempPath(), randomDirectoryName); 

     Directory.CreateDirectory(DirectoryPath); 
    } 

    public string DirectoryPath 
    { 
     get { return _directoryPath; } 
    } 

    public void Dispose() 
    { 
     try 
     { 
      if (Directory.Exists(_directoryPath)) 
       Directory.Delete(_directoryPath, true); 
     } 
     catch (IOException) 
     { 
      // Give other process a chance to release their handles 
      // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true/1703799#1703799 
      Thread.Sleep(0); 
      try 
      { 
       Directory.Delete(_directoryPath, true); 
      } 
      catch 
      { 
       var longDelayS = 2; 
       try 
       { 
        // This time we'll have to be _really_ patient 
        Thread.Sleep(TimeSpan.FromSeconds(longDelayS)); 
        Directory.Delete(_directoryPath, true); 
       } 
       catch (Exception ex) 
       { 
        throw new Exception(@"Could not delete " + GetType() + @" directory: """ + _directoryPath + @""" due to locking, even after " + longDelayS + " seconds", ex); 
       } 
      } 
     } 
    } 
} 

和骨架EmailSender

public class EmailSender 
{ 
    readonly SmtpClient _smtpClient; 

    public EmailSender(SmtpClient smtpClient) 
    { 
     if (smtpClient == null) 
      throw new ArgumentNullException("smtpClient"); 

     _smtpClient = smtpClient; 
    } 

    public void Send(string from, string recipients, string subject, string body) 
    { 
     _smtpClient.Send(from, recipients, subject, body); 
    } 
} 
+0

我尝试使用您的TemporaryDirectoryFixture作为AutoData。 Dispose方法被Xunit调用,但我得到一个IOException对路径的访问被拒绝。如果我在测试中使用了一个使用语句,它会起作用。也许Xunit跑步者有不同的权限比测试代码会导致这种情况? – 2015-07-27 05:10:46

+0

@EricRoller是v2还是v1?在这两种情况下,测试都在AppDomain内部运行(尽管v2最近添加了一个开关以允许禁止此操作)。然而,在v1和v2之间,参数的创建方式和/或Dispose会有很大的不同。在v1中,args的处理没有发生,没有太多的诡计(自定义'FactAttribute's等)。我没有花费足够的时间阅读有关“一次性”的文档,以了解除了说'做'使用'会很容易理解,除非您有足够的测试可以获益使它值得 – 2015-07-27 08:05:54

+0

我正在使用v2,并只是想出发生了什么。我修改了TemporaryDirectoryFixture来扩展DirectoryInfo。然后Autofixture使用随机数据调用所有公共设置器,这些数据在删除目录时会以某种方式导致访问被拒绝。我解决了这个问题,所有公共设置者都没有操作。感谢TemporaryDirectoryFixture代码,它使得编写小集成测试非常快捷。 – 2015-07-28 11:34:20