0x01 前言
單元測試,總是伴隨着我們的開發過程,優劣自行google。當然呢,不排除有些公司是不做單元測試的,
但是呢,學多一點東西用來防身還是可以的。
0x02 簡單的Demo
寫個兩數求和的方法,來進行簡單的測試。
1 namespace Catcher.Lib 2 { 3 public class Method 4 { 5 public int Add(int num1,int num2) 6 { 7 return num1 + num2; 8 } 9 } 10 }
新建一個測試項目,添加xunit的相關引用以及我們測試方法所在的程序。
編寫測試類MethodTest
1 using Xunit; 2 namespace Catcher.Lib.Test 3 { 4 public class MethodTest 5 { 6 Method method = new Method(); 7 [Fact] 8 public void add_two_integers_should_success() 9 { 10 int num1 = 3; 11 int num2 = 5; 12 int expected = 8; 13 int actual = method.Add(num1,num2); 14 Assert.Equal(expected,actual); 15 } 16 } 17 }
打開測試窗口,運行測試,看看測試結果
OK,測試通過。
注:要通過NuGet安裝xunit.runner.visualstudio才可以看到測試窗口!
0x03 結合Moq來模擬數據訪問層的操作
添加對應數據訪問層的接口和類,以及模型(這里沒有將模型單獨抽出來。)
我在這里添加了一個IUserDAL接口和UserDAL類
IUserDAL具體如下
1 using Catcher.Lib.Model; 2 using System.Collections.Generic; 3 namespace Catcher.Lib 4 { 5 public interface IUserDAL 6 { 7 IList<UserInfo> GetAllUsers(); 8 bool AddUser(UserInfo user); 9 UserInfo GetUser(int id); 10 } 11 }
UserDAL具體如下
1 using Catcher.Lib.Model; 2 using System.Collections.Generic; 3 using System.Linq; 4 namespace Catcher.Lib.Implement 5 { 6 public class UserDAL : IUserDAL 7 { 8 public bool AddUser(UserInfo user) 9 { 10 using (DB db = new DB()) 11 { 12 db.UserInfoes.Add(user); 13 return db.SaveChanges() > 0; 14 } 15 } 16 public IList<UserInfo> GetAllUsers() 17 { 18 using (DB db = new DB()) 19 { 20 return db.UserInfoes.ToList(); 21 } 22 } 23 public UserInfo GetUser(int id) 24 { 25 using (DB db = new DB()) 26 { 27 return db.UserInfoes.Find(id); 28 } 29 } 30 } 31 }
都是些簡單的操作,用到了EF,不做過多解釋。
在測試項目添加一個UserDALTest的測試類。
1 using Catcher.Lib.Model; 2 using Moq; 3 using System; 4 using System.Collections.Generic; 5 using Xunit; 6 namespace Catcher.Lib.Test 7 { 8 public class UserDALTest 9 { 10 private List<UserInfo> _userList; 11 private UserInfo _user; 12 public UserDALTest() 13 { 14 //fake data 15 _userList = new List<UserInfo>(); 16 _userList.Add(new UserInfo { UserID = 1, UserName="catcher", UserIsActive=true }); 17 _userList.Add(new UserInfo { UserID = 2, UserName = "hawk", UserIsActive = false }); 18 _user = new UserInfo() { UserID=3, UserIsActive=true, UserName = "tom" }; 19 } 20 [Fact] 21 public void get_all_users_should_success() 22 { 23 //arrange 24 var fakeObject = new Mock<IUserDAL>(); 25 fakeObject.Setup(x=>x.GetAllUsers()).Returns(_userList); 26 //act 27 var res = fakeObject.Object.GetAllUsers(); 28 //assert 29 Assert.Equal(2,res.Count); 30 } 31 [Fact] 32 public void add_a_user_should_success() 33 { 34 var fakeObject = new Mock<IUserDAL>(); 35 36 fakeObject.Setup(x => x.AddUser(It.IsAny<UserInfo>())).Returns(true); 37 var res = fakeObject.Object.AddUser(_user); 38 Assert.Equal<bool>(true,res); 39 } 40 [Fact] 41 public void add_a_user_should_fail() 42 { 43 var fakeObject = new Mock<IUserDAL>(); 44 fakeObject.Setup(x => x.AddUser(It.IsAny<UserInfo>())).Returns(false); 45 var res = fakeObject.Object.AddUser(_user); 46 Assert.Equal<bool>(false, res); 47 } 48 [Fact] 49 public void get_a_user_by_valid_id_should_success() 50 { 51 var fakeObject = new Mock<IUserDAL>(); 52 fakeObject.Setup(x=>x.GetUser(It.IsAny<int>())).Returns(_user); 53 var res = fakeObject.Object.GetUser(3); 54 Assert.Equal(3,res.UserID); 55 Assert.Equal("tom",res.UserName); 56 Assert.Equal(true,res.UserIsActive); 57 } 58 [Fact] 59 public void get_a_user_by_invalid_id_should_throw_exception() 60 { 61 var fakeObject = new Mock<IUserDAL>(); 62 fakeObject.Setup(x => x.GetUser(It.IsAny<int>())).Throws(new NullReferenceException()); 63 Assert.Throws<NullReferenceException>(()=> fakeObject.Object.GetUser(4)); 64 } 65 } 66 }
這里對上面的UserDAL進行簡單的說明,
在構造函數中制造了一個模擬的數據,
get_all_users_should_success 測試方法是測試GetAllUsers方法的。
add_a_user_should_success 測試方法是測試AddUser方法的,這個是添加成功的測試。
add_a_user_should_fail 測試方法是測試AddUser方法的,這個是添加失敗的測試。
get_a_user_by_valid_id_should_success 測試方法是測試GetUser方法的,這個是查詢成功的測試。
get_a_user_by_invalid_id_should_throw_exception 測試方法是測試GetUser方法的,這個是查詢拋出異常的測試。
注:測試方法的命名應盡可能包含其操作與結果(個人看法)。
運行測試效果如下:
0x04 寫在最后
平時要養成編寫單元測試的好習慣。