http://imPRove.dk/automated-testing-of-orcamdf-against-multiple-sql-server-versions/
自從我發(fā)布了OrcaMDF Studio,我已經(jīng)意識(shí)到SQL2005和SQL2008之間的一些系統(tǒng)表的差異。
這些差異導(dǎo)致OrcaMDF 解析失敗因?yàn)榇a是針對(duì)2008 R2的格式的
當(dāng)需要做SQL2005的兼容時(shí),我漸漸意識(shí)到我需要擴(kuò)大多個(gè)SQLSERVER版本的測(cè)試覆蓋,替代之前的只對(duì)一個(gè)版本的測(cè)試。
而且,我也需要對(duì)一些特定版本功能進(jìn)行特定的測(cè)試(例如:稀疏列測(cè)試只能運(yùn)行在SQLSERVER2008及以上版本)
NUnit TestCaseSourceAttribute 解決問(wèn)題
NUnit支持通過(guò)TestCase屬性進(jìn)行內(nèi)聯(lián)參數(shù)測(cè)試。更好的是,對(duì)于動(dòng)態(tài)測(cè)試用例我們還可以提供參數(shù)數(shù)據(jù),使用TestCaseSource屬性,使用TestCaseSource attribute。
首先,我實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的枚舉來(lái)覆蓋我目前工作所支持的版本:
public enum DatabaseVersion{ SqlServer2005, SqlServer2008, SqlServer2008R2,}
然后我創(chuàng)建SqlServerTestAttribute類(lèi),直接繼承自TestCaseSourceAttribute,就像這樣:
public class SqlServerTestAttribute : TestCaseSourceAttribute{ private static IEnumerable<TestCaseData> versions { get { foreach (var value in Enum.GetValues(typeof(DatabaseVersion))) yield return new TestCaseData(value).SetCategory(value.ToString()); } } public SqlServerTestAttribute() : base(typeof(SqlServerTestAttribute), "versions") { }}
這個(gè)SqlServerTestAttribute類(lèi)告訴TestCaseSourceAttribute 在私有靜態(tài)的版本屬性(private static)里去找測(cè)試用例的源數(shù)據(jù)。
版本屬性里枚舉出所有的DatabaseVersion值并一個(gè)接一個(gè)的返回它們——確保將測(cè)試類(lèi)別設(shè)置到DatabaseVersion值的名稱(chēng)
接下來(lái),我將當(dāng)前的測(cè)試轉(zhuǎn)換為使用新的SqlServerTest attribute,替代先前的vanilla NUnit Test attribute:
[SqlServerTest]public void HeapForwardedRecord(DatabaseVersion version){ ...}
這將導(dǎo)致我所有的測(cè)試都需要根據(jù)DatabaseVersion枚舉里面的每個(gè)枚舉值都運(yùn)行一次,自動(dòng)獲取輸入的版本參數(shù)里面的每一個(gè)值
支持不同的開(kāi)發(fā)環(huán)境現(xiàn)在,我不想強(qiáng)迫每個(gè)人都安裝所有版本的SQL Server--他們可能只是想軟件支持SQL Server 2005 & 2008R2就夠了。在OrcaMDF.Core.Tests項(xiàng)目里,我定義了每種受支持的測(cè)試數(shù)據(jù)庫(kù)的連接字符串,就像這樣
<connectionStrings> <clear/> <add name="SqlServer2005" connectionString="Data Source=.SQL2005;Integrated Security=SSPI"/> <add name="SqlServer2008R2" connectionString="Data Source=.;Integrated Security=SSPI"/></connectionStrings>
如果一個(gè)數(shù)據(jù)庫(kù)沒(méi)有相應(yīng)的連接字符串(名稱(chēng)對(duì)應(yīng)的DatabaseVersion 枚舉值)那么該版本的測(cè)試就不會(huì)運(yùn)行。因?yàn)檫@個(gè),我目前忽略SQL Server 2008 并且在我的機(jī)器上只安裝了SQL 2005 和SQL 2008R2
為了對(duì)當(dāng)前可用數(shù)據(jù)庫(kù)進(jìn)行過(guò)濾,我修改了我的測(cè)試用例讓基類(lèi)去運(yùn)行實(shí)際的測(cè)試,使用lambda表達(dá)式:
[SqlServerTest]public void HeapForwardedRecord(DatabaseVersion version){ RunDatabaseTest(version, db => { var scanner = new DataScanner(db); var rows = scanner.ScanTable("HeapForwardedRecord").ToList(); Assert.AreEqual(25, rows[0].Field<int>("A")); Assert.AreEqual("".PadLeft(5000, 'A'), rows[0].Field<string>("B")); Assert.AreEqual(28, rows[1].Field<int>("A")); Assert.AreEqual("".PadLeft(4000, 'B'), rows[1].Field<string>("B")); });}
這個(gè)RunDatabase 方法在SqlServerSystemTestBase類(lèi)里面聲明
protected void RunDatabaseTest(DatabaseVersion version, Action<Database> test){ string versionConnectionName = version.ToString(); // Only run test for this version if a connection string has been provided if (ConfigurationManager.ConnectionStrings[versionConnectionName] == null) Assert.Inconclusive(); // Setup database and store file paths, if we haven't done so already ensureDatabaseIsSetup(version); // Run actual test using (var db = new Database(databaseFiles[version])) test(db);}
如果對(duì)應(yīng)的連接字符串沒(méi)有在配置文件里面聲明,我們會(huì)放棄測(cè)試并且會(huì)將他標(biāo)記為不確定的- 根據(jù)當(dāng)前的配置情況我們根本不能運(yùn)行他。
接下來(lái),ensureDatabaseIsSetup()執(zhí)行通常的配置代碼(詳細(xì)內(nèi)容可以參考先前的文章)盡管這一次每個(gè)數(shù)據(jù)庫(kù)版本,每個(gè)測(cè)試固件都需要執(zhí)行。最后 一個(gè)OrcaMDF實(shí)例將會(huì)被創(chuàng)建并傳入實(shí)際的測(cè)試參數(shù)
支持不同SQLSERVER版本的特性正如前面提到的,我需要針對(duì)特定SQLSERVER版本的執(zhí)行的測(cè)試方法。標(biāo)準(zhǔn)的SqlServerTestAttribute 自動(dòng)枚舉所有的DatabaseVersion enumeration里面的值,不過(guò)我沒(méi)有理由再單獨(dú)創(chuàng)建一個(gè)SqlServer2005TestAttribute 就像這樣
public class SqlServer2005TestAttribute : TestCaseSourceAttribute{ private static IEnumerable<TestCaseData> versions { get { yield return new TestCaseData(DatabaseVersion.SqlServer2005).SetCategory(DatabaseVersion.SqlServer2005.ToString()); } } public SqlServer2005TestAttribute() : base(typeof(SqlServer2005TestAttribute), "versions") { }}
那如果需要將測(cè)試運(yùn)行在SQL Server 2008上呢?
public class SqlServer2008PlusTestAttribute : TestCaseSourceAttribute{ private static IEnumerable<TestCaseData> versions { get { foreach (var value in Enum.GetValues(typeof(DatabaseVersion))) if((DatabaseVersion)value >= DatabaseVersion.SqlServer2008) yield return new TestCaseData(value).SetCategory(value.ToString()); } } public SqlServer2008PlusTestAttribute() : base(typeof(SqlServer2008PlusTestAttribute), "versions") { }}
一旦我們有attributes,那么將會(huì)比較容易的對(duì)于我們的版本運(yùn)行單獨(dú)的測(cè)試
[SqlServer2008PlusTest]public void ScanAllNullSparse(DatabaseVersion version){ RunDatabaseTest(version, db => { var scanner = new DataScanner(db); var rows = scanner.ScanTable("ScanAllNullSparse").ToList(); //稀疏列 Assert.AreEqual(null, rows[0].Field<int?>("A")); Assert.AreEqual(null, rows[0].Field<int?>("B")); });}
對(duì)于ReSharper test runner 的支持為了運(yùn)行測(cè)試,我們需要ReSharper 6.0 因?yàn)镽eSharper 5.1不支持TestCaseSource attribute。一旦你執(zhí)行了測(cè)試,你將會(huì)看到下面的測(cè)試結(jié)果(已經(jīng)支持SQL Server 2005 & 2008 R2 測(cè)試)
每一個(gè)測(cè)試用例都會(huì)自動(dòng)對(duì)多個(gè)版本的DatabaseVersion 進(jìn)行測(cè)試(除了解析測(cè)試,因?yàn)樗麤](méi)有實(shí)現(xiàn)SqlServerSystemTestBase 因此不能運(yùn)行多版本測(cè)試)。
因?yàn)槲覜](méi)有對(duì) SQL Server 2005作出支持所以大部分對(duì) SQL Server 2005的測(cè)試都失敗。當(dāng)我運(yùn)行測(cè)試的時(shí)候所有SQL2008的測(cè)試都是inconclusive 。
最后,所有對(duì)于SQL2008R2的測(cè)試都通過(guò)了
測(cè)試過(guò)濾很明顯,我們不能總是對(duì)所有版本的SQLSERVER進(jìn)行測(cè)試,那太浪費(fèi)時(shí)間了。其中一種禁用對(duì)特定版本的測(cè)試的方法就是刪除連接字符串。
然而,這樣依然會(huì)產(chǎn)生不明確的輸出,而且總是修改配置文件會(huì)很麻煩
不幸的是,ReSharper test runner不支持對(duì)使用TestCaseSourceAttribute創(chuàng)建的參數(shù)化測(cè)試的category 過(guò)濾。我已經(jīng)在 YouTRACK上面開(kāi)了一個(gè)特性要求,我希望ReSharper團(tuán)隊(duì)會(huì)考慮將這個(gè)特性添加到ReSharper6.1。如果你也覺(jué)得這個(gè)特性很棒,請(qǐng)考慮投票支持
幸運(yùn)的是,NUnit test runner 不支持這種過(guò)濾。在NUnit test runner里打開(kāi)OrcaMDF.Core.Tests程序集會(huì)給你以下結(jié)果
注意在我們運(yùn)行測(cè)試之前,Nunit怎么知道參數(shù)化的測(cè)試參數(shù)的!同時(shí)也需要注意Nunit怎么讓DifferingRecordFormats 測(cè)試只運(yùn)行在SQL2008或以上 ,
而FGSpecificClusteredAllocation測(cè)試只讓運(yùn)行在SQL2005或以上
幸好,如果我們點(diǎn)擊Categories的tab標(biāo)簽,我們就可以獲得測(cè)試類(lèi)別的清單
通過(guò)顯式選擇特定的版本類(lèi)別,我們可以選擇運(yùn)行某些版本,一旦運(yùn)行了,沒(méi)有被選擇的類(lèi)別類(lèi)別頭部的小圓點(diǎn)會(huì)變成灰色
可以注意到 運(yùn)行時(shí)間用了89秒,基本上1秒一個(gè)測(cè)試,98%的時(shí)間花費(fèi)在了lob類(lèi)型特性的測(cè)試上。由于類(lèi)別格式,我能夠在主要的測(cè)試類(lèi)別上進(jìn)行選擇,從而輕松過(guò)濾掉長(zhǎng)時(shí)間運(yùn)行的測(cè)試項(xiàng)目并只關(guān)注快速完成的那些類(lèi)別。
lob 類(lèi)型特別需要進(jìn)行測(cè)試因?yàn)樵跀?shù)據(jù)庫(kù)啟動(dòng)之前他們涉及大量的磁盤(pán)活動(dòng),配置表和配置行的創(chuàng)建
展望未來(lái)添加新版本就猶如安裝SQLSERVER那樣簡(jiǎn)單,在配置項(xiàng)里添加一個(gè)連接字符串,最后,添加SQLSERVER版本名字進(jìn)去DatabaseVersion 枚舉里。就這么多了。
進(jìn)一步,在某種程度上我需要按順序測(cè)試多種升級(jí)途徑。基于我自己做的一些測(cè)試,一個(gè)從SQL Server 2005升級(jí)到SQLSERVER2008 R2之后的數(shù)據(jù)庫(kù)
可能跟在SQLSERVER2008 R2本地創(chuàng)建的數(shù)據(jù)庫(kù)有不同,或者從SQL2008升級(jí)到SQL2008R2。因此,我需要測(cè)試多種不同的升級(jí)途徑確保完全的兼容性。
然而,兼容性測(cè)試的優(yōu)先級(jí)在我的測(cè)試優(yōu)先級(jí)列表里比較低,因?yàn)檫@些兼容性測(cè)試會(huì)花費(fèi)很多時(shí)間
第十一篇完
新聞熱點(diǎn)
疑難解答
圖片精選