2010-02-04 83 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