Post Page Advertisement [Top]

     Merhaba,
     Bu yazımızda Unit Test Nedir ? Konu başlıklı yazımıza devam edip unit test yazarken ihtiyaç duyduğumuz nesneleri çağırmak yerine mocking dediğimiz kavram (taklit etme) yöntemi ile servis çağrımı yapacağız.


    Neden buna ihtiyaç duyarız ? Çünkü birim testlerinin amacı ilgili birimi izole edip beklenen sonucu bize verip vermediğini görmektir. Bir modülü birim teste tabi tutarken bağlılığı olan fakat test kaleminde olmayan elemanları : servisler , repository'ler vb. mocklanır. Yani cevap vermiş gibi davranması sağlanır. İhtiyaç duyduğumuz servisleri test ederken gerçekten servisi gerçekten çağırmak servisin tetiklenmesi sonucu işlem yapmasına sebebiyet verir bu durum test yazarken istenmeyen bir durumdur.

Okurken ne dinlemeli ?

 
  İlk olarak Unit test projemiz için hazırladığımız EndGameHelmetMessaging projesine bir WCF servis ekleyelim. Projemize referans alıp bu servisi kullanan işlemler oluşturalım. Solution'a sağ tıklayıp -> Add- > New Project diyerek aşağıdaki gibi bir WCF servis oluşturalım. İsmini HelmetMessagingService olarak isimlendirelim.


IHelmetMessagingService arayüzümüze ilk olarak baktığımızda OperationContract filed'i altına serviste yer alacak metodlarımızı belirlediğimizi görüyoruz bu servis için sadece mesaj gönderimi yapan Send metodumuz olduğunu düşünelim.


    [ServiceContract]
    public interface IHelmetMessagingService
    {
            [OperationContract]
            string Send(MessageItem message);

    }


Send metodu MessageItem türünden bir parametre almaktadır. Dolayısı ile MessageItem contract'ını belirleyelim.


    [DataContract]
    public class MessageItem
    {

        string stringMessage = "";
        string stringSenderId = "";
        string stringReceiverId = "";


        [DataMember]
        public string Message
        {
            get { return stringMessage; }
            set { stringMessage = value; }
        }

        [DataMember]
        public string SenderId
        {
            get { return stringSenderId; }
            set { stringSenderId = value; }
        }

        [DataMember]
        public string ReceiverId
        {
            get { return stringReceiverId; }
            set { stringReceiverId = value; }
        }
    }


MessageItem sınıfı Message,SenderId,RecieverId property'lerinden oluşmaktadır. Şimdi gelelim Send metodunun işlevini kodlamaya bunun için .svc uzantılı dosyaya sağ tıklayı VievCode diyerek svc.cs kısmına geçelim biz Send metodonun bir echo servis gibi davranmasını istediğimiz için aşağıdaki gibi kodlayalım:


    public class HelmetMessagingService : IHelmetMessagingService
    {
        public string Send(MessageItem message)
        {
            return string.Format("You send: {0}", message.Message);
        }
    }


WCF servisimiz hazır. .svc uzantılı dosyaya sağ tıklayıp View in Browser dediğimizde WCF servisimizin ayağa kalktığını görebiliriz. EndGameHelmetMessaging uygulamamızda referans almak için servis end pointini not alalım. localhost://...



 EndGameHelmetMessaging projesinde References 'e sağ tıklayıp Add Service reference ekleyelim ve not ettiğimiz url 'i yazıp servisi bulmasını sağlayalım.



Şimdi servisi kullanan metodumuzu hazırlayalım.


    public MessageResponse MessageSendToService(MessageRequest request)
    {
        MessageResponse response = new MessageResponse();
        string returnString;


        EndGameHelmetMessaging.MessagingService.MessageItem message_item;

        message_item = new EndGameHelmetMessaging.MessagingService.MessageItem
        {
            Message = request.Message,
            SenderId = request.SenderId,
            ReceiverId = request.ReceiverId
        };


        EndGameHelmetMessaging.MessagingService.HelmetMessagingServiceClient service = new EndGameHelmetMessaging.MessagingService.HelmetMessagingServiceClient();
        returnString = service.Send(message_item);

        if (returnString == string.Format("You send: {0}", message_item.Message))
        {
            response.IsSuccess = true;
            response.ResponseCode = ErrorCodes.success_message;
        }

        return response;
    }


Eğer gönderdiğimiz mesaj bize aynı formatta gelmiş ise reponse 'u başarılı olarak işaretliyoruz.
WCF servisi oluşturduk , projemize referans alıp kullandık şimdi gelelim Test projemizde servis'in istediğimiz gibi çalışıp çalışmadığını kontrol etmek için  Unit test yazmaya, bunun için daha önce oluşturduğumuz ve Solution'a eklediğimiz .Test ile biten projemize yeni bir sınıf ekleyelim.



 
Bu sınıfa test metodumuzu yazmadan önce servisi test için mocklayabilmemiz gerekir bu entegrasyonu da Dependency Injection kullanarak yapabiliriz. Bunu için EndGameHelmetMessaging ve  EndGameHelmetMessaging.Test projelerimize Unity nuget paketini ekleyelim.



MessageManager sınıfında bazı değişiklikler yapalım :


    public MessagingManager()
    {
        this.MessagingValidator = new MessagingValidator();
        this.MessagingRepository = new MessagingRepository();
        this.service = new HelmetMessagingServiceClient();

    }

    // constructor for unit test
    public MessagingManager(bool isUnitTest, IHelmetMessagingService wcfMockObject)
    {
        UnityContainer IoC = new UnityContainer();

        IoC.RegisterInstance<IHelmetMessagingService>(wcfMockObject);
        this.service = IoC.Resolve<IHelmetMessagingService>();

    }


...


public MessageResponse MessageSendToService(MessageRequest request)
    {
        MessageResponse response = new MessageResponse();
        string returnString;


        MessageItem message_item;

        message_item = new MessageItem
        {
            Message = request.Message,
            SenderId = request.SenderId,
            ReceiverId = request.ReceiverId
        };


       // EndGameHelmetMessaging.MessagingService.HelmetMessagingServiceClient service = new EndGameHelmetMessaging.MessagingService.HelmetMessagingServiceClient();
        returnString = service.Send(message_item);

        if (returnString == string.Format("You send: {0}", message_item.Message))
        {
            response.IsSuccess = true;
            response.ResponseCode = ErrorCodes.success_message;
        }


        return response;
    }



Yukarıda görüldüğü gibi Unit Test için farklı bir constructor yazdık. Eğer unit test kodumuz çalışacak ise ikinci yapılandırıcıyı çağırıp Unity IOC container'ına WCF servis mock'umuzu inject etmiş olacağız. MessageSendToService metodumuzda ise servis instance'sini yorum satırı haline getirdim.

 Test sınıfına geçmeden önce mock 'la için kullanacağımız Moq nuget paketini Test projemize ekleyelim.


Test metodumuzu yazalım:


        [TestMethod]
        public void Should_We_Successfully_Send_Message()
        {

            string val = "You send: helloSteve";

            var expected = new MessageResponse
            {
                IsSuccess = true,
                ResponseCode = ErrorCodes.success_message
            };

            // mock wcf interface
            Mock<IHelmetMessagingService> wcfMock = new Mock<IHelmetMessagingService>();
            wcfMock.Setup<string>(s => s.Send(It.IsAny<MessageItem>())).Returns(val);

            // create object to register with IoC
            IHelmetMessagingService wcfMockObject = wcfMock.Object;

            // register instance
            //UnityContainer IoC = new UnityContainer();
            // IoC.RegisterInstance<IHelmetMessagingService>(wcfMockObject);
          

            // create ServiceAgent object using parameterized constructor (for unit test)
            MessagingManager serviceAgent = new MessagingManager(true, wcfMockObject);

            var messageRequest = new MessageRequest
            {
                MessageId = 1,
                Message = "helloSteve",
                SenderId = "tony_stark_0001",
                ReceiverId = "steve_rogers_003"
            };

            // method call to be tested
            var actual  = serviceAgent.MessageSendToService(messageRequest);

            // verify if the expected method called during test or not
            wcfMock.Verify(srv => srv.Send(It.IsAny<MessageItem>()), Times.Exactly(1));


            Assert.AreEqual(expected.IsSuccess, actual.IsSuccess);
            Assert.AreEqual(expected.ResponseCode, actual.ResponseCode);


        }


Yukarıda görüldüğü gibi  Mock ile wcf servisimizi taklit edip döneceği sonucu val değişkeninde setliyoruz. Daha sonra IOC container'a wcfMock objesini parametre olarak vererek MessageManager constructor'ında register etmesini sağlıyoruz.


            // create ServiceAgent object using parameterized constructor (for unit test)
            MessagingManager serviceAgent = new MessagingManager(true, wcfMockObject);


Verify metodu ile de gerçekten wcf mock'unun çağrılıp çağrılmadığını kontrol ederek artık Unit test aşamasında son adım olan Asset adımı ile beklenti ve mevcut çıktıları karşılaştırıyoruz.

Test projesine EndGameMessageHelmet vasıtası ile referans aldığım wcf servisininin  endpoint 'inde IHelmetMessagingService interfacesini  bulamadığı için Test projesinin app.config' ine wcf servisin binding' lerini kopyaladım. Size bu sorun olabilir de olmaya bilir de aklınızda bulunsun. Çözüm  burada.

Kaynak :
https://www.codeproject.com/Articles/318260/%2FArticles%2F318260%2FHow-to-Mock-a-WCF-Service

Proje kodunu buradan indirip inceleyebilirsiniz.

Sağlıkla kalın,
huzurlu kalın.

Hiç yorum yok:

Yorum Gönder

Bottom Ad [Post Page]