[ASP.NET]單元測試工具-NMock
摘要
本篇主要著重在ASP.NET的單元測試工具NMock上,
在使用NMock時心中燃起了一個疑問,
.NET平台已經有提供像是NUnit這種自動化單元測試的framwork,
為什麼還要用NMock呢?
NMock還是有其獨特的優點,
當我們的待測程式有透過介面(Interface)呼叫其他外部程式時,
則可使用NMock來模擬該介面,以降低程式間的耦合性。
以下的應用實例將說明如何善用NMock工具來協助我們進行單元測試。
先附上NMock2的下載網址:http://sourceforge.net/projects/nmock2/
step1:先建立一個主控台應用程式專案,並定義一個簡單的Interface。
step3:針對Hello.Greet() 這個method進行單元測試。
對我們來說,IPerson.GetName()這個Interface並不是我們在進行Hello.Greet()單元測試所關注的。
故我們模擬(mock) IPerson這個Interface ,並用hardcode的方法給定GetName()的值。
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5:
6: namespace NMock
7: {
8:
9: class Hello
10: {
11: static void Main(string[] args)
12: {
13: }
14:
15: IPerson person; //--This method invokes the interface method.
16:
17: public Hello(IPerson person)
18: {
19: this.person = person;
20: }
21: public String Greet()
22: {
23: return "Hello " + person.GetName();
24: }
25:
26: }
27: }
step4:建立單元測試。
step5:在測試專案中,它會自動產生程式碼。
我們將他改成NMock程式碼。
1: /// <summary>
2: ///Greet 的測試
3: ///</summary>
4: [TestMethod()]
5: public void GreetTest()
6: {
7: //1. 建立一個mock object
8: Mockery personMock = new Mockery();
9: //2. 用mock object來模擬IPerson這個Interface
10: IPerson p = personMock.NewMock<IPerson>();
11: //3. 給定模擬結果一個值, ex:GetName()給他returnValue = “Neil"
12: string returnValue = "Neil";
13: //4. 模擬呼叫IPerson.GetName() 這個method的結果
14: Expect.Once.On(p).Method("GetName").WithNoArguments().Will(Return.Value(returnValue));
15: //5. 建立target class object
16: Hello h = new Hello(p);
17: //6. 呼叫target test method
18: Assert.AreEqual("Hello Neil", h.Greet());
19: }
step6:測試->執行->可選目前內容中的測試或方案中所有測試。
step7:我們試著開啟另一個測試專案,並將其預設結果設為("Hello Pou")。
1: /// <summary>
2: ///Greet 的測試
3: ///</summary>
4: [TestMethod()]
5: public void GreetTest()
6: {
7: Mockery personMock = new Mockery();
8: IPerson p = personMock.NewMock<IPerson>();
9: string returnValue = "Neil";
10: Expect.Once.On(p).Method("GetName").WithNoArguments().Will(Return.Value(returnValue));
11: Hello h = new Hello(p);
12: Assert.AreEqual("Hello Neil", h.Greet());
13: }
14:
15: /// <summary>
16: ///Greet 的測試
17: ///</summary>
18: [TestMethod()]
19: public void GreetTest1()
20: {
21: Mockery personMock = new Mockery();
22: IPerson p = personMock.NewMock<IPerson>();
23: string returnValue = "Neil";
24: Expect.Once.On(p).Method("GetName").WithNoArguments().Will(Return.Value(returnValue));
25: Hello h = new Hello(p);
26: Assert.AreEqual("Hello Pou", h.Greet());
27: }
step8:可以看到第二個測試專案失敗。
因為returnValue = "Neil",故測試的預其結果應為("Hello Neil"),
與我們預設的結果("Hello Pou")不同,故產生錯誤訊息。
小結:
Mock 在每個測試中都必須明確定義所有例外狀況,
在此應用實例只是簡單的小程式,
當我們專案中所要測試的目標與Mock Object之間的互動越密切,
我們就要定義更多的期望值,這將有可能使我們的測試變得耗工又費時。