這是一個相當古老的問題。不過, 似乎也很久沒遇到過了。當今天再度遇到時, 突然被嚇了一跳。問題是這樣的, 當我們建立單元測試專案時, 如果你看到測試不成功的原因是什麼「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 中使用不同的資料庫, 這麼一來, 測試的資料才不會跟正式資料庫或開發資料庫混雜在一起。
參考資料: