Daha önceki yazımızda Birim Test Nedir konusuna değinmiştik ve birim test için kullanılabilecek frameworkleri vermiştik. Bu yazımızda Db operasyonları olan bir projede unit test yazmak istersek ne yapardık bu soruya cevap arıyor olacağız.
Bir UserRepository sınıfımız olsun ve bu repository için unit test metotları yazıyor olalım. Peki ama test metotlarını yazarken nasıl bir yol izleyeceğiz ? Her bir test case’i için gidip veritabanına dummy kayıtlar atıp CRUD işlemleri yapmamamız gerekir. Bu gibi durumlar için mocking dediğimiz “alaycı” veya “sahte” kayıtlar oluşturmamızı sağlayan library’ler bulunmakta. Bu library’lerden Moq’u kullanarak sahte nesneler üreterek UserRepository için basit bir test projesi yazacağız. Peki bu Moq nedir?
Moq Nedir ?
Mock kavramı istediğimiz bir nesnenin yerine geçebilen fake nesnelerdir. Bu objelerin istediğimiz gibi davranmalarını sağlayabiliriz. Moq’ta bu tarz işlemleri handle eden ve mock objelerini bize hazır sunan bir kütüphane.
Örnek Proje
Örnek projemiz için öncelikle bir tane UnitTestWithMoq adımda Console Application oluşturalım ve içerisine IUserRepository.cs arayüzünü ve User.cs sınıfını aşağıdaki gibi tanımlayalım.
1 2 3 4 5 6 7 8 9 10 11 | namespace UnitTestWithMoq { public interface IUserRepository { IList<User> GetAll(); User GetById(int userId); void Insert(User user); void Update(User user); void Delete(int Id); } } |
1 2 3 4 5 6 7 8 9 | namespace UnitTestWithMoq { public class User { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } } |
Şimdi ise UnitTestWithMoq.Test adında test projemizi oluşturalım ve UnitTestWithMoq projemizi referans olarak test projemize ekleyelim. Sonrasında test projemize Nuget üzerinden Moq kütüphanesini kuralım.
Tools > Nuget Package Manager > Package Manager Console > PM> Install-Package Moq
Kurulum işlemi tamamlandıktan sonra UserRepositoryTest adında bir class oluşturalım.
İlk olarak UserRepository için
gerekli olan setup işlemlerini yapalım. Setup işlemi kısaca
repository’nin içerisindeki metotların sahte objelerle işlemleri
yapmasını sağlayacak kodları yazmak diyebiliriz. Mocking setup ile ilgili kodlarımız aşağıdaki gibi olacaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | namespace UserRepositoryTest { [TestClass] public class UserRepositoryTest { public readonly IUserRepository MockUserRepository; public UserRepositoryTest() { // Test metotları genelinde kullanacağımız User listesi var userList = new List<User> { new User {Id=1,FirstName="User1",LastName="User1LastName" }, new User {Id=2,FirstName="User2",LastName="User2LastName" }, new User {Id=3,FirstName="User3",LastName="User3LastName" } }; // Mock the Products Repository using Moq var mockUserRepository = new Mock<IUserRepository>(); // GetAll metodu için setup işlemi mockUserRepository.Setup(mr => mr.GetAll()).Returns(userList); // GetById metodu için setup işlemi mockUserRepository.Setup(mr => mr.GetById(It.IsAny<int>())).Returns((int i) => userList.Single(x => x.Id == i)); // Insert için setup işlemi mockUserRepository.Setup(mr => mr.Insert(It.IsAny<User>())).Callback( (User target) => { userList.Add(target); }); // Update için setup işlemi mockUserRepository.Setup(mr => mr.Update(It.IsAny<User>())).Callback( (User target) => { var original = userList.Where(q => q.Id == target.Id).Single(); if (original == null) { throw new InvalidOperationException(); } original.FirstName = target.FirstName; original.LastName = target.LastName; }); // Test metotlarından erişilebilmesi için global olarak tanımladığımız MockUserRepository'e yukarıdaki setup işlemlerini atıyoruz this.MockUserRepository = mockUserRepository.Object; } } } |
Peki biz bu kodlarda ne yapıyoruz.
IUserRepository diye CRUD işlemlerinin yapıldığı bir class’ın ve bu class içerisinde bulunan GetAll, GetById, Insert, Update, Delete metotları için tanımlanan mocking veya kandırmaca işlemleri yukarıdaki gibidir. Database üzerinden bu işlemleri yapmak yerine rahatça userList array’i üzerinden bu işlemleri yapabilir.
GetAll metodunu çağırarak bize veri döndüğünü gösteren test metodu.
1 2 3 4 5 6 7 | [TestMethod] public void GetAll_Than_Check_Count_Test() { var expected = this.MockUserRepository.GetAll().Count; Assert.IsNotNull(expected); // test not null Assert.IsTrue(expected > 0);// test GetAll returns user objects } |
GetById metodu için doğru objeyi return edip etmediği durumu için test metodu.
1 2 3 4 5 6 7 8 9 | [TestMethod] public void GetById_Than_Check_Correct_Object_Test() { var actual = new User { Id = 2, FirstName = "User2", LastName = "User2LastName" }; var expected = this.MockUserRepository.GetById(2); Assert.IsNotNull(expected); // Test is not null Assert.IsInstanceOfType(expected, typeof(User)); // Test type Assert.AreEqual(actual.Id, expected.Id); // test correct object found } |
Insert işleminden sonra GetAll metodundan dönen object sayısı doğrumu testi
1 2 3 4 5 6 7 8 9 | [TestMethod] public void Insert_User_Than_Check_GetAll_Count_Test() { var actual = this.MockUserRepository.GetAll().Count + 1; var user = new User { Id = 4, FirstName = "User4", LastName = "User4LastName" }; this.MockUserRepository.Insert(user); var expected = this.MockUserRepository.GetAll().Count; Assert.AreEqual(actual, expected); } |
GetById metoduna hatalı bir Id ile çağrım yapıldığında Exception döneceği durumu için test metodu.
1 2 3 4 5 6 | [TestMethod] [ExpectedException(typeof(InvalidOperationException))]//Eğer beklediğimiz bir exception var ise bu şekilde tanımlayabiliriz public void GetyId_With_Undefined_Id_Than_Exception_Occurred_Test() { var expected = this.MockUserRepository.GetById(It.IsAny<int>()); } |
Update işlemi sonrasında GetById yapılarak dönen nesnede bulunan değerler doğrumu test metodu.
1 2 3 4 5 6 7 8 9 10 | [TestMethod] public void Update_User_Than_Check_It_Is_Updated_Test() { var actual = new User { Id = 2, FirstName = "User2_Updated", LastName = "User2LastName_Updated" }; this.MockUserRepository.Update(actual); var expected = this.MockUserRepository.GetById(actual.Id); Assert.IsNotNull(expected); Assert.AreEqual(actual.FirstName, expected.FirstName); Assert.AreEqual(actual.LastName, expected.LastName); } |
Test metotlarını yazdıktan sonra Run All Tests diyerek testlerimizi çalıştırıp success-fail durumlarını görebiliriz.
Bu yazımızda Moq kullanarak basitçe bir Unit Test projesi hazırladık. Artık yazılım dünyasında unit test olmazsa olmazdır. Umarım faydalı olmuştur.
Yararlanılan kaynaklar
http://www.canertosuner.com/post/moq-kullanarak-unittest-yazma
Hiç yorum yok:
Yorum Gönder