在單元測試程式中取得 Connection 字串

這是一個相當古老的問題。不過, 似乎也很久沒遇到過了。當今天再度遇到時, 突然被嚇了一跳。問題是這樣的, 當我們建立單元測試專案時, 如果你看到測試不成功的原因是什麼「System.ArgumentException: 此處不允許應用程式相對虛擬路徑 '~/'」之類莫名其妙的錯誤的話, 大概就是依照以下解法就對了...

這是一個相當古老的問題。不過, 似乎也很久沒遇到過了。當今天再度遇到時, 突然被嚇了一跳。問題是這樣的, 當我們建立單元測試專案時, 如果你看到測試不成功的原因是什麼「System.ArgumentException: 此處不允許應用程式相對虛擬路徑 '~/'」之類莫名其妙的錯誤的話, 大概就是依照以下解法就對了。

這問題之所以發生, 就是因為你使用了類似如下的方法去取得 Web.config 中的連線字串:

Configuration rootWebConfig =
                    System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/");

System.Configuration.ConnectionStringSettings connString;
if (0 < rootWebConfig.ConnectionStrings.ConnectionStrings.Count)
{
    connString =
        rootWebConfig.ConnectionStrings.ConnectionStrings["MyConnectionString1"];
    return connString.ToString();
}
else
    return null;

然而, 當單元測試的程式在執行時, 由於它並沒有產生 HttpContext, 它並不會取被測試專案中取得 Web.config 的內容。相反的, 它會認為這個單元測試專案並不是一個 Web 專案, 所以自然不能使用 "~/" 這種相對路徑。同樣的, 如果你改用 HttpRuntime.AppDomainAppVirtualPath 而不是使用 "~/", 情況也是一樣。

該怎麼解決? 很簡單, 先判斷 HttpContext 存不存在; 若不存在, 則改用 OpenExeConfiguration, 讓它去存取測試專案中的 App.config 檔案中的 Configuration 區段。改過的程式如下:

using System.Web.Hosting;
using System.Web.Configuration;
using System.Configuration;
...
Configuration rootWebConfig =
                    (HttpContext.Current != null)?
                        WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath):
                        ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); // 以下省略

不過, 你必須在測試專案中新增一個 App.config 檔案, 然後把原來專案中 Web.config 中的 connectionStrings 區段拷貝過去 :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="ConnectionString1" connectionString="Data Source=abc; Initial Catalog=abc; Persist Security Info=True; User ID=abc; Password=abc"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

如此, 無論是原專案或者測試專案, 都能夠正確取得連線字串了。甚至, 你可以 (也應該) 在測試專案中的 App.config 中使用不同的資料庫, 這麼一來, 測試的資料才不會跟正式資料庫或開發資料庫混雜在一起。

參考資料:

 


Dev 2Share @ 點部落