Daha önceki yazımızda Unit Test Nedir konusuna değinmiştik ve Unit test için kullanılabilecek frameworkleri vermiştik. Bu yazımızda Db operasyonları olan bir projede unit test yazmak istesek ne yapardık bu soruya cevap arıyor olacağız.

Bir UserRepository class’ı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 database saçma sapan fake 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 objenin yerine geçebilen fake objelerdir. 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 User.cs ve IUserRepository.cs class’larını aşağıdaki gibi tanımlayalım

[csharp]namespace UnitTestWithMoq {     public class User     {         public int Id { get; set; }         public string FirstName { get; set; }         public string LastName { get; set; }     } }[/csharp]
[csharp]namespace UnitTestWithMoq {     public interface IUserRepository     {         IList GetAll();         User GetById(int userId);         void Insert(User user);         void Update(User user);         void Delete(int Id);     } }[/csharp]

Ş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 User Repository 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.

[csharp]namespace UserRepositoryTest {     [TestClass]     public class UserRepositoryTest     {         public readonly IUserRepository MockUserRepository;         public UserRepositoryTest()         {             // Test metotları genelinde kullanacağımız User listesi             var userList = new List             {                 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();             // 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())).Returns((int i) => userList.Single(x => x.Id == i));             // Insert için setup işlemi             mockUserRepository.Setup(mr => mr.Insert(It.IsAny())).Callback(                 (User target) =>                 {                     userList.Add(target);                 });             // Update için setup işlemi             mockUserRepository.Setup(mr => mr.Update(It.IsAny())).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;         }  }}[/csharp]

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.

[csharp][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         }[/csharp]

GetById metodu için doğru objeyi return edip etmediği durumu için test metodu.

[csharp][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         }[/csharp]

Insert işleminden sonra GetAll metodundan dönen object sayısı doğrumu testi

[csharp][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);         }[/csharp]

GetById metoduna hatalı bir Id ile çağrım yapıldığında Exception döneceği durumu için test metodu.

[csharp][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());         }[/csharp]

Update işlemi sonrasında GetById yapılarak dönen nesnede bulunan değerler doğrumu test metodu.

[csharp][TestMethod]         public void Ipdate_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);         }[/csharp]

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.

Kaynak Kodu

Yararlanılan kaynaklar