使用 Visual Studio 對公共方法進行單元測試,跟以前 NUnit 一樣,都是引用需要的類,然后對公共方法進行測試。
但是 Visual Studio 還可以對類的私有方法進行測試。而Visual Studio 不允許測試代碼跟實際代碼放在一個項目中,我們來看看是Visual Studio UnitTest如何做的。
比如我們有這樣一個私有方法
?

namespace?ClassLibrary1
{

public?class?DivisionClass
{

private?int?Divide_private(int?numerator,?int?denominator)
{
return?numerator?/?denominator;
}
}
}?
我們只要在這個私有方法的右鍵菜單中選擇 創(chuàng)建單元測試,系統(tǒng)就自動產(chǎn)生了這個私有方法的單元測試代碼。
下面我們來分析產(chǎn)生的單元測試代碼,看Visual Studio UnitTest 是如何對私有方法進行單元測試的
簡單來說,Visual Studio UnitTest 生成私有方法的單元測試時,將自動創(chuàng)建一個私有訪問器。私有訪問器是測試方法用于訪問私有代碼的方法。單元測試生成對私有訪問器的調(diào)用,然后通過私有訪問器來調(diào)用私有方法。私有訪問器駐留在測試項目中的文件中;因此將被編譯為測試項目程序集。
具體來看測試項目:
首先我們可以看到一個名為 VSCodeGenAccessors.cs 的新文件被創(chuàng)建,
這個文件包含兩個類:
internal 類型的 BaseAccessor 類 和 派生自它的 ClassLibrary1_DivisionClassAccessor 類
BaseAccessor 類是通用的訪問器基類。
ClassLibrary1_DivisionClassAccessor 類 則是對你要訪問類的私有方法進行了反射封裝,這樣你就可以通過操作這個類來操作該私有方法了。如下面代碼:
using?Microsoft.VisualStudio.TestTools.UnitTesting;


namespace?TestProject1
{
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration",?"1.0.0.0")]

internal?class?BaseAccessor?
{

protected?Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject?m_privateObject;


protected?BaseAccessor(object?target,?Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType?type)?
{
m_privateObject?=?new?Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target,?type);
}

protected?BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType?type)?:

this(null,?type)?
{}


internal?virtual?object?Target?
{

get?
{
return?m_privateObject.Target;
}
}


public?override?string?ToString()?
{
return?this.Target.ToString();
}


public?override?bool?Equals(object?obj)?
{

if?(typeof(BaseAccessor).IsInstanceOfType(obj))?
{
obj?=?((BaseAccessor)(obj)).Target;
}
return?this.Target.Equals(obj);
}


public?override?int?GetHashCode()?
{
return?this.Target.GetHashCode();
}
}

[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration",?"1.0.0.0")]

internal?class?ClassLibrary1_DivisionClassAccessor?:?BaseAccessor?
{

protected?static?Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType?m_privateType?=?new?Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::ClassLibrary1.DivisionClass));

internal?ClassLibrary1_DivisionClassAccessor(global::ClassLibrary1.DivisionClass?target)?:

base(target,?m_privateType)?
{}


internal?int?Divide_private(int?numerator,?int?denominator)?
{

object[]?args?=?new?object[]?
{
numerator,
denominator};

int?ret?=?((int)(m_privateObject.Invoke("Divide_private",?new?System.Type[]?
{
typeof(int),
typeof(int)},?args)));
return?ret;
}
}
}


注意:當您更改正在測試的代碼文件中的私有方法時,這個訪問器可能無法正常工作,需要重新生成專用訪問器(ClassLibrary1_DivisionClassAccessor 類)。
整理一下就是:
這個訪問器,是通過反射的方式實現(xiàn)的。
VSUT利用自動代碼生成技術(shù),在單元測試項目中先來給你要測試的類生成一個名字叫XXXAccessor的訪問器。
這個訪問器會把需要測試類的需要測試的私有方法暴露出來,這種方式,無論是私有還是公共的屬性和方法。這種方式可以很方便的給測試方法搭建測試環(huán)境,MOCK對象的注入也容易了。在測試調(diào)用的時候,就簡單的只有下面的代碼了:
[DeploymentItem("ClassLibrary1.dll")]
[TestMethod()]
public?void?Divide_privateTest()


{
DivisionClass?target?=?new?DivisionClass();
TestProject1.ClassLibrary1_DivisionClassAccessor?accessor?=?new? TestProject1.ClassLibrary1_DivisionClassAccessor(target);
int?numerator?=?4;
int?denominator?=?0;
int?expected?=?0;
int?actual;
actual?=?accessor.Divide_private(numerator,?denominator);
Assert.AreEqual(expected,?actual,?"ClassLibrary1.DivisionClass.Divide_private?未返回所需的值。");
Assert.Inconclusive("驗證此測試方法的正確性。");
}

Visual Studio 2005 新增的測試功能使我們的開發(fā)工作更為快捷,代碼質(zhì)量在一定程度上有所提高。想必大家對類的單元測試已經(jīng)比較熟悉,這里我們來看看它提供的另一項更為有趣的測試——用戶界面自動化測試。事實上這個測試的本質(zhì)仍是單元測試,單元測試的各種方法在用戶界面測試中仍然可用。
我們以一個簡單的 Windows Form 應(yīng)用程序為例(在 Visual Studio 2005 Team System 下演示,其它版本亦可參考)。如圖所示,這是一個一元二次方程的求解程序。

在 Visual Studio 2005 中加載這個程序的工程,切換到待測試窗體(Form1)的源代碼視圖。添加一個用戶界面測試最簡單的方法是在事件函數(shù)聲明代碼上右擊鼠標,在快捷菜單中點擊“Create Unit Tests”。在彈出的對話框中點選待測試的函數(shù)(特別是事件函數(shù)),確定。當然,手工添加一個單元測試項目也是可以的,但通過快捷菜單自動生成的代碼中包含了一些測試輔助類和對象的聲明,使用起來更加方便。
本例中,我們由 btnWorkOut_Click 創(chuàng)建單元測試,自動生成的代碼如下:
[DeploymentItem("XandY.exe")]
[TestMethod()]
public void btnWorkOut_ClickTest()
{
Form1 target = new Form1();
MyTestProject.XandY_Form1Accessor accessor = new MyTestProject.XandY_Form1Accessor(target);
object sender = null; // TODO: Initialize to an appropriate value
EventArgs e = null; // TODO: Initialize to an appropriate value
accessor.btnWorkOut_Click(sender, e);
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
熟悉單元測試的朋友應(yīng)該明白 [TestMethod()] 屬性的含義。在這個測試函數(shù)中,target 是待測試窗體的一個實例。sender 和 e 是各個事件函數(shù)必備的參數(shù),一般情況下取 null 即可。最重要的是 accessor 對象,它是我們進行用戶界面自動化測試的“總代理”。通過它可以訪問到待測試窗體的各個方法、屬性和控件,并可調(diào)用控件已聲明的各個事件。由此,我們可以用 accessor 模擬使用者通過鍵盤、鼠標對用戶界面的各項操作,同時即時獲知程序中各個變量的狀態(tài)。有興趣的朋友可以讀讀 XandY_Form1Accessor 類的定義,了解這個“總代理”工作的奧秘。
我們對測試代碼進行以下修改,以便對程序運行的正確性進行測試。
[DeploymentItem("XandY.exe")]
[TestMethod()]
public void btnWorkOut_ClickTest()
{
Form1 target = new Form1();
MyTestProject.XandY_Form1Accessor accessor = new MyTestProject.XandY_Form1Accessor(target);
object sender = null; // TODO: Initialize to an appropriate value
EventArgs e = null; // TODO: Initialize to an appropriate value
target.Show();
target.Refresh();
System.Threading.Thread.Sleep(1000);
accessor.textBox1.Text = "2";
accessor.textBox2.Text = "4";
accessor.textBox3.Text = "2";
target.Refresh();
System.Threading.Thread.Sleep(1000);
accessor.btnWorkOut_Click(sender, e);
target.Refresh();
Assert.IsTrue(accessor.d >= 0);
Assert.IsNotNull(accessor.xx);
Assert.IsNotNull(accessor.xy);
Console.WriteLine("X1 = " + accessor.textBox4.Text);
Console.WriteLine("X2 = " + accessor.textBox5.Text);
System.Threading.Thread.Sleep(1000);
target.Close();
}
以上代碼中,我們通過 target.Show() 呈現(xiàn)窗體,通過 target.Refresh() 可以即時地刷新窗體內(nèi)容在屏幕的顯示,通過 System.Threading.Thread.Sleep(1000) 來延時。這幾段代碼都不是必需的,加入它們是為了便于程序反應(yīng)和測試者觀察,我們也完全可以在不顯示用戶界面的情況下更快地運行自動測試。至于用 Assert 來監(jiān)控變量狀態(tài)和用 Console 做輸出,用過單元測試的朋友都應(yīng)該了解。
此時,我們運行這個測試,就會在屏幕上先后看到窗體被加載,三個文本框被填入數(shù)據(jù),計算結(jié)果出現(xiàn)在下面的文本框中,最后窗體被關(guān)閉。
再來看看測試結(jié)果的輸出,符合我們的預期。
Visual Studio 2005 的用戶界面自動化測試就是這么簡單。對于一般的測試,它使測試人員不必深究應(yīng)用程序底層的實現(xiàn)。當然,對于本例這樣簡單的程序,我們用不著這么麻煩的測試,但是對于用戶界面更加復雜的程序,操作上存在更多的組合方式,手工測試的繁瑣程度以及查找問題的難度便大大上升了。使用 Visual Studio 2005 提供的自動化測試手段將在很大程度上減輕測試人員的負擔。有興趣的朋友甚至可以在這個基礎(chǔ)上進行二次開發(fā),引入自動化測試腳本等專業(yè)測試方案,實現(xiàn)通用性更強的用戶界面自動化測試