{"id":1034,"date":"2017-01-21T19:40:11","date_gmt":"2017-01-21T17:40:11","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=1034"},"modified":"2017-01-21T19:40:11","modified_gmt":"2017-01-21T17:40:11","slug":"microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/","title":{"rendered":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon"},"content":{"rendered":"<p>Merhaba arkada\u015flar.<\/p>\n<p>Yine microservice mimarilerine y\u00f6nelik bir konu ile kar\u015f\u0131n\u0131zday\u0131m. Sizlerde biliyorsunuz ki son d\u00f6nemlerde neredeyse t\u00fcm ilgi alan\u0131m\u0131, microservice\u00a0mimarileri ve MQ(Message Queue) tabanl\u0131 sistemlere yo\u011funla\u015ft\u0131rd\u0131m. Bu sistemler her ne kadar bir \u00e7ok derdimizi \u00e7\u00f6zseler bile, asla kusursuz bir \u015fey olmad\u0131\u011f\u0131 gibi beraberlerinde getirdi\u011fi baz\u0131 ek maliyetler de bulunmaktad\u0131r.<\/p>\n<p>Microservice mimarilerine ge\u00e7ilmesinde, belki en \u00f6nemli concern&#8217;lerden birisi de <strong>test<\/strong> konusudur. Peki nas\u0131l?<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-1035 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/consumer-contract-test-geek.jpg\" alt=\"consumer-contract-test-geek\" width=\"480\" height=\"469\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/consumer-contract-test-geek.jpg 566w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/consumer-contract-test-geek-300x293.jpg 300w\" data-sizes=\"(max-width: 480px) 100vw, 480px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 480px; --smush-placeholder-aspect-ratio: 480\/469;\" \/><\/p>\n<p>Sistemimizde -n tane servis&#8217;in var oldu\u011funu d\u00fc\u015f\u00fcnelim ve hepsi loosely coupled bir \u015fekilde hayatlar\u0131n\u0131 s\u00fcrd\u00fcrmektedir. Biliyoruz ki bitmek bilmeyen business ihtiya\u00e7lar\u0131n\u0131n kar\u015f\u0131s\u0131nda, sisteme s\u00fcrekli ek \u00f6zellikler kat\u0131lmaktad\u0131r. Bunlar\u0131n yan\u0131 s\u0131ra ger\u00e7ek hayatta legacy application&#8217;lar\u0131n, bir anda yeni mimarilere de ge\u00e7irilebilmesi de m\u00fcmk\u00fcn olmamaktad\u0131r. Bu sebep ile her bir mod\u00fcl\u00fc par\u00e7a par\u00e7a microservis&#8217;lere ta\u015f\u0131mam\u0131z gerekebilece\u011fi i\u00e7in s\u00fcrekli bir <strong>deployment<\/strong> ihtiyac\u0131 do\u011facakt\u0131r. Peki bu deployment&#8217;lar s\u0131ras\u0131nda hangi servisin nereyi etkileyece\u011fini nas\u0131l bilebiliriz ve ilgili servisi t\u00fcketen di\u011fer servislerin bozulmayaca\u011f\u0131n\u0131 nas\u0131l test edebiliriz?<\/p>\n<p>En s\u0131k kar\u015f\u0131la\u015f\u0131lan durumlardan birisi, endpoint&#8217;lerin client&#8217;\u0131n etkile\u015fimi olmaks\u0131z\u0131n de\u011fi\u015ftirilmesidir.<\/p>\n<h4>\u00d6rne\u011fin:<\/h4>\n<ul>\n<li>GET \/api\/customer \u015feklinde iken, GET \/api\/customers olarak endpoint&#8217;in de\u011fi\u015ftirilmesi<\/li>\n<li>GET \/api\/customers\/1 \u015feklinde m\u00fc\u015fteri bilgilerini d\u00f6nerken, art\u0131k GET \/api\/customers\/1\/detail \u015feklinde d\u00f6n\u00fclmesi gibi senaryolar<\/li>\n<\/ul>\n<p>\u0130\u015fte bu tarz durumlar kar\u015f\u0131s\u0131nda insan bazen, ke\u015fke monolith bir application geli\u015ftiriyor olsayd\u0131k demiyor de\u011fil. :) \u0130\u015fin geyi\u011fi bir\u00a0yana monolith bir application i\u00e7in integration test&#8217;ler yazmak, birden \u00e7ok distributed microservice&#8217;lere implemente etmekten \u00e7ok daha basit.<\/p>\n<p>Konumuza geri d\u00f6necek olursak e\u011fer, microservice yap\u0131lar\u0131nda bu tarz problemler i\u00e7in asl\u0131nda yeni olmayan bir yakla\u015f\u0131m\/pattern mevcuttur. Bir ka\u00e7 d\u00f6nemdir\u00a0microservice mimarilerinin pop\u00fclerle\u015fmesi ile \u00f6nem kazanan bu yakla\u015f\u0131m, <strong>Consumer Driven Contracts Testing<\/strong>\u00a0olarak ge\u00e7mektedir.<\/p>\n<p>Consumer Driven Contract temel olarak API contract&#8217;lar\u0131n\u0131n kullan\u0131mlar\u0131n\u0131 client&#8217;lara\u00a0tan\u0131mlayarak, de\u011fi\u015fimler s\u0131ras\u0131nda ya\u015fanabilecek problemlerin bir nebze \u00f6n\u00fcne ge\u00e7ebilmeye yard\u0131mc\u0131 olmaktad\u0131r. Consumer Driven Contracts&#8217;\u0131 .NET taraf\u0131nda implementasyonu i\u00e7in <a href=\"http:\/\/www.pact.io\" target=\"_blank\"><em><strong>Pact<\/strong> <\/em><\/a>isminde harika bir framework mevcuttur. Makale s\u0131ras\u0131nda ger\u00e7ekle\u015ftirecek oldu\u011fumuz \u00f6rne\u011fimizde, Pact framework&#8217;\u00fcn\u00fc kullanarak <strong>contract specification<\/strong>, <strong>contract verification<\/strong> ve <strong>contract distribution<\/strong> nas\u0131l ger\u00e7ekle\u015ftirilir gibi konular\u0131 ele al\u0131yor olaca\u011f\u0131z.<\/p>\n<h4>Consumer Driven Contracts Testing Nas\u0131l \u00c7al\u0131\u015f\u0131r?<\/h4>\n<p>Consumer Driven Contracts&#8217;\u0131n \u00e7al\u0131\u015fma mant\u0131\u011f\u0131 basic concept olarak a\u015fa\u011f\u0131daki gibidir.<\/p>\n<ol>\n<li>Consumer, ilgili service&#8217;in request ve response&#8217;undan ne bekledi\u011fini tan\u0131mlar<\/li>\n<li>Provider ve Consumer bu contract&#8217;lar i\u00e7in verify i\u015flemini ger\u00e7ekle\u015ftirir<\/li>\n<li>Sonras\u0131nda ise Provider, ilgili contract&#8217;lar\u0131n yerine getirildi\u011fini s\u00fcrekli olarak do\u011frular ve bu sayede hangi Consumer&#8217;lar\u0131n de\u011fi\u015fimler kar\u015f\u0131s\u0131nda nas\u0131l\u00a0etkilendikleri\u00a0g\u00f6r\u00fcn\u00fcr k\u0131l\u0131n\u0131r<\/li>\n<\/ol>\n<h4>Pact Framework&#8217;\u00fcn\u00fcn Baz\u0131 Avantajlar\u0131<\/h4>\n<ul>\n<li>End-to-end olarak ortamlar\u0131 kurmaya gerek yoktur<\/li>\n<li>Manuel testing gerektirmez<\/li>\n<li>Contract&#8217;lar\u0131n \u00fcretimi ve do\u011frulanmas\u0131 Pact taraf\u0131ndan otomatik olarak ger\u00e7ekle\u015ftirilir<\/li>\n<li>Olu\u015fturulan Pact&#8217;ler sayesinde de, readable bir \u015fekilde Api Contract dok\u00fcmantasyonu da olu\u015fturulmu\u015f olunur<\/li>\n<\/ul>\n<p>Bunlara ek olarak, farkl\u0131 teknolojiler ile geli\u015ftirilmi\u015f service&#8217;ler aras\u0131ndaki entegrasyonu da m\u00fcmk\u00fcn k\u0131lar. Pact\u00a0initial olarak Ruby i\u00e7in geli\u015ftirilmi\u015f bir framework&#8217;d\u00fcr ve \u015fuan bir \u00e7ok programlama dilinde yayg\u0131n bir hale gelmi\u015f durumdad\u0131r. Contract verify i\u015flemi i\u00e7in olu\u015fturulacak olan pact file&#8217;\u0131 JSON format\u0131nda olaca\u011f\u0131 i\u00e7in, farkl\u0131 platformlar aras\u0131nda da kolayl\u0131kla implemente edilebilmesi m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<h4>Pact Framework&#8217;\u00fcn\u00fcn Implementasyonu<\/h4>\n<h5>1) Consumer ve Pact&#8217;lerinin Olu\u015fturulmas\u0131<\/h5>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/define-consumer-expectations.jpg\"><img decoding=\"async\" class=\"aligncenter wp-image-1046 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/define-consumer-expectations.jpg\" alt=\"define-consumer-expectations\" width=\"672\" height=\"469\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/define-consumer-expectations.jpg 877w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/define-consumer-expectations-300x209.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/define-consumer-expectations-230x160.jpg 230w\" data-sizes=\"(max-width: 672px) 100vw, 672px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 672px; --smush-placeholder-aspect-ratio: 672\/469;\" \/><\/a><\/p>\n<p>Implementasyon s\u0131ras\u0131nda ilk ger\u00e7ekle\u015ftirecek oldu\u011fumuz k\u0131s\u0131m, yukar\u0131daki diyagram\u0131n sol taraf\u0131 olacakt\u0131r. Burada sonras\u0131nda olu\u015fturacak oldu\u011fumuz Provider&#8217;\u0131 yani API&#8217;\u0131 consume edecek bir Consumer yazaca\u011f\u0131z. Consumer i\u00e7erisinde API contract&#8217;lar\u0131na y\u00f6nelik request ve response&#8217;lar\u0131n Pact&#8217;leri \u00e7\u0131kart\u0131p, file system&#8217;da verify i\u015flemi i\u00e7in persist edece\u011fiz.<\/p>\n<p>\u0130kinci k\u0131s\u0131mda olu\u015fturacak oldu\u011fumuz Provider, m\u00fc\u015fteri bilgilerini \u00e7eken bir API olsun. Bu API&#8217;\u0131n GET method&#8217;u &#8220;\/api\/customers\/1&#8221; URI&#8217;\u0131 ile, &#8220;1&#8221; numaral\u0131 id&#8217;ye sahip customer&#8217;\u0131 d\u00f6ns\u00fcn. \u00d6ncelikle ilk ad\u0131m olarak serialization i\u015flemlerinde kolayl\u0131k sa\u011flamas\u0131 a\u00e7\u0131s\u0131ndan, API&#8217;dan repsonse olarak d\u00f6n\u00fcyor olaca\u011f\u0131m\u0131z contract&#8217;\u0131 ekleyerek ba\u015flayal\u0131m. Bunun i\u00e7in &#8220;ConsumerDrivenContractsTestingSample&#8221; isminde yeni bir blank solution olu\u015fturup, i\u00e7erisine &#8220;Contracts&#8221; isminde bir class library ekleyelim.<\/p>\n<p>Eklemi\u015f oldu\u011fumuz bu library i\u00e7erisinde, &#8220;Customer.cs&#8221; isminde yeni bir class ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true \">namespace Contracts\r\n{\r\n    public class Customer\r\n    {\r\n        public int Id { get; set; }\r\n        public string FullName { get; set; }\r\n    }\r\n}<\/pre>\n<p>Contract k\u0131sm\u0131 bu kadar.<\/p>\n<p>Diyagram\u0131n ilk k\u0131s\u0131mdaki Consumer taraf\u0131n\u0131 kodlamaya ba\u015flayabiliriz. Solution \u00fczerine structured g\u00f6r\u00fcnebilmesi a\u00e7\u0131s\u0131ndan &#8220;Service Consumer&#8221; isminde bir klas\u00f6r olu\u015fturup, i\u00e7erisine &#8220;CustomerApiServiceConsumer&#8221; isminde bir class library ekleyelim. Bu library i\u00e7erisinde, biraz \u00f6nce bahsetmi\u015f oldu\u011fum Customer API&#8217;\u0131 consume edebilmemizi sa\u011flayan client k\u0131sm\u0131n\u0131 kodlayaca\u011f\u0131z. Client&#8217;\u0131 olu\u015fturma i\u015flemine ba\u015flamadan \u00f6nce REST call&#8217;lar\u0131 s\u0131ras\u0131nda, kolayl\u0131k sa\u011flamas\u0131 a\u00e7\u0131s\u0131ndan Nuget Package Manager \u00fczerinden &#8220;RestSharp&#8221; paketini &#8220;CustomerApiServiceConsumer&#8221; library&#8217;sine kural\u0131m ve &#8220;Contracts&#8221; library&#8217;sini referans olarak da g\u00f6sterelim.<\/p>\n<p>Kurulum i\u015fleminden sonra &#8220;CustomerApiClient.cs&#8221; isminde yeni bir class ekleyelim ve client&#8217;\u0131\u00a0a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">using Contracts;\r\nusing RestSharp;\r\n\r\nnamespace CustomerApiServiceConsumer\r\n{\r\n    public class CustomerApiClient\r\n    {\r\n        private readonly RestClient _restClient;\r\n\r\n        public CustomerApiClient(string baseUri)\r\n        {\r\n            _restClient = new RestClient(baseUri);\r\n        }\r\n\r\n        public Customer Get(int id)\r\n        {\r\n            var request = new RestRequest($\"\/api\/customers\/{id}\", Method.GET) {RequestFormat = DataFormat.Json};\r\n            request.AddHeader(\"Accept\", \"application\/json\");\r\n\r\n            var result = _restClient.Execute&lt;Customer&gt;(request);\r\n\r\n            return result.Data;\r\n        }\r\n    }\r\n}<\/pre>\n<p>Olu\u015fturmu\u015f oldu\u011fumuz &#8220;CustomerApiClient&#8221; i\u00e7erisinde &#8220;RestSharp&#8221; \u0131n client&#8217;\u0131n\u0131 kullanarak, &#8220;\/api\/customers\/{id}&#8221; resource&#8217;una basic bir GET request&#8217;i\u00a0yap\u0131yoruz. Request sonucunda ise geriye &#8220;Customer&#8221; result&#8217;\u0131n\u0131 d\u00f6n\u00fcyoruz.<\/p>\n<p>\u015eimdi s\u0131ra geldi test projesini olu\u015fturmaya. Olu\u015fturacak oldu\u011fumuz bu test projesi, servis&#8217;i kullanacak\u00a0olan service consumer&#8217;\u0131 temsil ediyor olacak ve burada &#8220;Customer API&#8221; a y\u00f6nelik <strong>Pact<\/strong>&#8216;leri \u00e7\u0131kart\u0131p, test case&#8217;lerini yazaca\u011f\u0131z. Solution \u00fczerindeki &#8220;Service Consumer&#8221; klas\u00f6r\u00fcn\u00fcn i\u00e7erisine, &#8220;CustomerApiServiceConsumer.Tests&#8221; isminde yeni bir Unit Test projesi\u00a0olu\u015ftural\u0131m. Unit Test projesinin \u00fczerine, \u00f6ncelikle test i\u015flemlerinde baz\u0131 fonksiyonlar\u0131ndan yararlanabilmek i\u00e7in &#8220;xunit&#8221; test framework&#8217;\u00fcn\u00fc ve &#8220;xunit.runner.visualstudio&#8221; paketini, Nuget Package Manager \u00fczerinden kural\u0131m. Kurulum i\u015fleminin ard\u0131ndan makale giri\u015finde de bahsetmi\u015f oldu\u011fumuz, Consumer Driven Contracts Testing yazabilmemize olanak sa\u011flayan &#8220;PactNet&#8221; paketini de Nuget Package Manager \u00fczerinden kural\u0131m.\u00a0Nuget \u00fczerindeki kurulumlar\u0131n ard\u0131ndan, &#8220;Contracts&#8221; ve &#8220;CustomerApiServiceConsumer&#8221; library&#8217;lerini referans olarak ekleyelim.<\/p>\n<p>Burada kodlamaya ilk olarak Customer API&#8217;\u0131n pact&#8217;ini olu\u015fturmak ile ba\u015flayaca\u011f\u0131z. Bu k\u0131s\u0131mlarda referans ald\u0131\u011f\u0131m yer ise, Pact framework&#8217;\u00fcn\u00fcn .net implementasyon\u00a0k\u0131sm\u0131n\u0131n bulundu\u011fu github adresidir. Makale sonunda sizlerle payla\u015f\u0131yor olaca\u011f\u0131m. Konumuza devam edecek olursak, &#8220;ConsumerCustomerApiPact.cs&#8221; isminde yeni bir class ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">using System;\r\nusing PactNet;\r\nusing PactNet.Mocks.MockHttpService;\r\n\r\nnamespace CustomerApiServiceConsumer.Tests\r\n{\r\n    public class ConsumerCustomerApiPact : IDisposable\r\n    {\r\n        public IPactBuilder PactBuilder { get; private set; }\r\n        public IMockProviderService MockProviderService { get; private set; }\r\n\r\n        public int MockServerPort =&gt; 1234;\r\n        public string MockProviderServiceBaseUri =&gt; $\"http:\/\/localhost:{MockServerPort}\";\r\n\r\n        public ConsumerCustomerApiPact()\r\n        {\r\n            PactBuilder = new PactBuilder();\r\n            PactBuilder.ServiceConsumer(\"CustomerApiServiceConsumer\").HasPactWith(\"CustomerApi.Host\");\r\n\r\n            MockProviderService = PactBuilder.MockService(MockServerPort);\r\n        }\r\n\r\n        public void Dispose()\r\n        {\r\n            PactBuilder.Build();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&#8220;ConsumerCustomerApiPact&#8221; class&#8217;\u0131 i\u00e7erisinde bulunan &#8220;PactBuilder&#8221; ile, bir adet mock servis aya\u011fa kald\u0131r\u0131yoruz. Bu mock servis, &#8220;MockServerPort&#8221; property&#8217;si \u00fczerinden alm\u0131\u015f oldu\u011fu port bilgisi ile arka plan\u0131nda Nancy Self Hosting paketini kullanarak\u00a0olu\u015fmaktad\u0131r. Buradaki dikkat edilmesi gereken nokta ise &#8220;PactBuilder.ServiceConsumer()&#8221; method&#8217;unda servis&#8217;i consume edecek yerin neresi oldu\u011fu, &#8220;HasPactWith()&#8221; method&#8217;unda ise hangi provider ile pact&#8217;e sahip oldu\u011funu belirtiyoruz. Dispose method&#8217;u ile ger\u00e7ekle\u015ftirilen <strong>deferred execution\u00a0<\/strong>i\u015flemi ile bu pact&#8217;i kullanacak olan test case&#8217;inin, ilgili test senaryosunu ger\u00e7ekle\u015ftirmesinden sonra Customer API&#8217;a ait pact&#8217;leri olu\u015fturmas\u0131\u00a0sa\u011flanmaktad\u0131r.<\/p>\n<p>\u015eimdi yine &#8220;CustomerApiServiceConsumer.Tests&#8221; projesi i\u00e7erisine, &#8220;CustomerApiConsumerTests.cs&#8221; isminde bir Unit Test class&#8217;\u0131 ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">using System.Collections.Generic;\r\nusing Contracts;\r\nusing PactNet.Mocks.MockHttpService;\r\nusing PactNet.Mocks.MockHttpService.Models;\r\nusing Xunit;\r\n\r\nnamespace CustomerApiServiceConsumer.Tests\r\n{\r\n    public class CustomerApiConsumerTests : IClassFixture&lt;ConsumerCustomerApiPact&gt;\r\n    {\r\n        private readonly IMockProviderService _mockProviderService;\r\n        private readonly string _mockProviderServiceBaseUri;\r\n\r\n        public CustomerApiConsumerTests(ConsumerCustomerApiPact data)\r\n        {\r\n            _mockProviderService = data.MockProviderService;\r\n            _mockProviderServiceBaseUri = data.MockProviderServiceBaseUri;\r\n\r\n            data.MockProviderService.ClearInteractions();\r\n        }\r\n\r\n        [Fact]\r\n        public void GetCustomer_WhenTheCustomerIdGreaterThanZero_ReturnCustomer()\r\n        {\r\n            \/\/Arrange\r\n            int customerId = 1;\r\n\r\n            _mockProviderService\r\n                .Given(\"There is a customer with id 1\")\r\n                .UponReceiving(\"A GET request to retrieve the customer\")\r\n                .With(new ProviderServiceRequest\r\n                {\r\n                    Method = HttpVerb.Get,\r\n                    Path = \"\/api\/customers\/\" + customerId,\r\n                    Headers = new Dictionary&lt;string, string&gt;\r\n                    {\r\n                        {\"Accept\", \"application\/json\"}\r\n                    }\r\n                })\r\n                .WillRespondWith(new ProviderServiceResponse\r\n                {\r\n                    Status = 200,\r\n                    Headers = new Dictionary&lt;string, string&gt;\r\n                    {\r\n                        {\"Content-Type\", \"application\/json; charset=utf-8\"}\r\n                    },\r\n                    Body = new Customer\r\n                    {\r\n                        Id = 1,\r\n                        FullName = \"G\u00f6khan G\u00f6kalp\"\r\n                    }\r\n                });\r\n\r\n            var consumer = new CustomerApiClient(_mockProviderServiceBaseUri);\r\n\r\n            \/\/Act\r\n            var result = consumer.Get(1);\r\n\r\n            \/\/Assert\r\n            Assert.NotNull(result);\r\n\r\n            _mockProviderService.VerifyInteractions();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&#8220;xunit&#8221; test paketi ile gelen &#8220;IClassFixture&lt;T&gt;&#8221; interface&#8217;inin i\u00e7erisine set etti\u011fimiz &#8220;ConsumerCustomerApiPact&#8221; class&#8217;\u0131n\u0131, herhangi bir test case&#8217;i execute olmadan \u00f6nce pact class&#8217;\u0131n\u0131 execute ediyor ve constructor \u00fczerinden pact&#8217;in instance&#8217;\u0131n\u0131 inject ediyor. &#8220;MockProviderService.ClearInteractions()&#8221; method&#8217;u ile de, \u00f6nceden kay\u0131t edilmi\u015f bir\u00a0interaction varsa, test run edilmeden \u00f6nce temizlemektedir.<\/p>\n<p>\u015eimdi gelelim as\u0131l test case&#8217;ine. &#8220;GetCustomer_WhenTheCustomerIdGreaterThanZero_ReturnCustomer&#8221; ismindeki test case&#8217;i ile isminden de anla\u015f\u0131labilece\u011fi gibi, customer id&#8217;si s\u0131f\u0131rdan b\u00fcy\u00fck ise ilgili customer&#8217;\u0131 getirmesini istiyoruz. Buradaki i\u015flemleri fluent bir \u015fekilde &#8220;ConsumerCustomerApiPact&#8221; i\u00e7erisinden gelen &#8220;IMockProviderService&#8221; ile ger\u00e7ekle\u015ftiriyoruz. Burada yer alan &#8220;Given()&#8221; ve &#8220;UponReceiving()&#8221; fluent method&#8217;lar\u0131 ile, pact&#8217;in readability a\u00e7\u0131s\u0131ndan anla\u015f\u0131l\u0131r\u00a0olabilmesi i\u00e7in ne al\u0131naca\u011f\u0131n\u0131 ve ne al\u0131nd\u0131\u011f\u0131 gibi bilgileri giriyoruz.&#8221;With()&#8221; ve &#8220;WillRespondWith&#8221; fluent method&#8217;lar\u0131 ile ise, provider&#8217;a nas\u0131l bir request ge\u00e7ece\u011fimizi ve bunun sonucunda nas\u0131l bir response elde edece\u011fimizi tan\u0131ml\u0131yoruz. Dikkat ederseniz bu noktada asl\u0131nda bir nevi provider&#8217;\u0131n endpoint dok\u00fcmantasyonunu da olu\u015fturuyor gibiyiz. Asl\u0131nda gibiyiz de de\u011fil, olu\u015fturuyoruz her bir endpoint i\u00e7in. :)<\/p>\n<p>Sonras\u0131nda ise art\u0131k, \u00f6ncesinde olu\u015fturmu\u015f oldu\u011fumuz client&#8217;\u0131 kullanarak, &#8220;_mockProviderServiceBaseUri&#8221;\u00a0ile mock servis \u00fczerinden &#8220;consumer.Get(1);&#8221; method&#8217;unu \u00e7a\u011f\u0131r\u0131yoruz. Bu i\u015flemin sonucunda e\u011fer result null de\u011filse, pact&#8217;i olu\u015fturabilmesi i\u00e7in interaction&#8217;\u0131 verify ederek, mock provider \u00fczerinde tekrardan kay\u0131tl\u0131 hale getiriyoruz.<\/p>\n<p>Test Explorer \u00fczerinden &#8220;GetCustomer_WhenTheCustomerIdGreaterThanZero_ReturnCustomer&#8221; method&#8217;unu \u00e7al\u0131\u015ft\u0131ral\u0131m ve sorunsuz bir \u015fekilde implementasyonu ger\u00e7ekle\u015ftirdi isek, test&#8217;in ba\u015far\u0131l\u0131 bir \u015fekilde ge\u00e7ti\u011fini g\u00f6rebilece\u011fiz.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/test-explorer.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1051 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/test-explorer.jpg\" alt=\"test-explorer\" width=\"534\" height=\"241\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/test-explorer.jpg 534w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/test-explorer-300x135.jpg 300w\" data-sizes=\"(max-width: 534px) 100vw, 534px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 534px; --smush-placeholder-aspect-ratio: 534\/241;\" \/><\/a><\/p>\n<p>Yukar\u0131daki resimde g\u00f6r\u00fcld\u00fc\u011f\u00fc gibi test&#8217;i \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131mda ba\u015far\u0131l\u0131 bir \u015fekilde test i\u015flemi ger\u00e7ekle\u015fti. \u015eimdi as\u0131l bu i\u015flemin sonucunda hat\u0131rlarsak &#8220;ConsumerCustomerApiPact&#8221; olu\u015ftururken Dispose k\u0131sm\u0131nda\u00a0ger\u00e7ekle\u015ftirilen\u00a0deferred execution ile &#8220;MockProviderService&#8221; \u00fczerine register edilmi\u015f request ve beklenen response senaryolar\u0131 buradan&#8221;Build()&#8221; method&#8217;u ile tetikleniyordu. Bu i\u015flem pact file&#8217;\u0131n\u0131n &#8220;<em>\\CustomerApiServiceConsumer.Tests\\pacts<\/em>&#8221; dizini alt\u0131nda a\u015fa\u011f\u0131daki gibi olu\u015fmas\u0131n\u0131 sa\u011flam\u0131\u015ft\u0131r.<\/p>\n<pre class=\"lang:js decode:true \">{\r\n  \"provider\": {\r\n    \"name\": \"CustomerApi.Host\"\r\n  },\r\n  \"consumer\": {\r\n    \"name\": \"CustomerApiServiceConsumer\"\r\n  },\r\n  \"interactions\": [\r\n    {\r\n      \"description\": \"A GET request to retrieve the customer\",\r\n      \"provider_state\": \"There is a customer with id 1\",\r\n      \"request\": {\r\n        \"method\": \"get\",\r\n        \"path\": \"\/api\/customers\/1\",\r\n        \"headers\": {\r\n          \"Accept\": \"application\/json\"\r\n        }\r\n      },\r\n      \"response\": {\r\n        \"status\": 200,\r\n        \"headers\": {\r\n          \"Content-Type\": \"application\/json; charset=utf-8\"\r\n        },\r\n        \"body\": {\r\n          \"Id\": 1,\r\n          \"FullName\": \"G\u00f6khan G\u00f6kalp\"\r\n        }\r\n      }\r\n    }\r\n  ],\r\n  \"metadata\": {\r\n    \"pactSpecificationVersion\": \"1.1.0\"\r\n  }\r\n}<\/pre>\n<p>Pact dosyas\u0131 ne kadar da okunabilir de\u011fil mi? Art\u0131k Provider k\u0131sm\u0131n\u0131 haz\u0131rlamaya ba\u015flayabiliriz.<\/p>\n<h5>2) Provider&#8217;\u0131n Olu\u015fturulmas\u0131 ve\u00a0Verification<\/h5>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/verify-expectations-on-provider.png\"><img decoding=\"async\" class=\"aligncenter wp-image-1052 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/verify-expectations-on-provider.png\" alt=\"verify-expectations-on-provider\" width=\"664\" height=\"467\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-expectations-on-provider.png 885w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-expectations-on-provider-300x211.png 300w\" data-sizes=\"(max-width: 664px) 100vw, 664px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 664px; --smush-placeholder-aspect-ratio: 664\/467;\" \/><\/a><\/p>\n<p>Art\u0131k bu k\u0131s\u0131mda Provider \u00fczerinden Consumer&#8217;\u0131n olu\u015fturmu\u015f oldu\u011fu pact&#8217;leri alarak, test API server&#8217;\u0131 \u00fczerinden pact&#8217;ler do\u011frultusunda verify i\u015flemini ger\u00e7ekle\u015ftirece\u011fiz. Solution \u00fczerine &#8220;Service Provider&#8221; isminde yeni bir klas\u00f6r daha ekleyerek, i\u00e7erisine &#8220;CustomerApi.Host&#8221; isminde bir console application projesi olu\u015ftural\u0131m. Projeyi olu\u015fturduktan sonra Nuget Package Manager \u00fczerinden &#8220;Microsoft.AspNet.WebApi.OwinSelfHost&#8221; paketini kural\u0131m.<\/p>\n<p>Kurulum i\u015flemlerinin ard\u0131ndan API&#8217;\u0131 owin ile host edebilmek i\u00e7in &#8220;Startup.cs&#8221; isminde yeni bir class ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">using System.Web.Http;\r\nusing Owin;\r\n\r\nnamespace CustomerApi.Host\r\n{\r\n    public class Startup\r\n    {\r\n        public void Configuration(IAppBuilder app)\r\n        {\r\n            \/\/ Configure Web API for self-host. \r\n            var config = new HttpConfiguration();\r\n\r\n            config.MapHttpAttributeRoutes();\r\n\r\n            config.Routes.MapHttpRoute(\r\n                name: \"DefaultApi\",\r\n                routeTemplate: \"api\/{controller}\/{id}\",\r\n                defaults: new { id = RouteParameter.Optional }\r\n            );\r\n\r\n            app.UseWebApi(config);\r\n        }\r\n    }\r\n}<\/pre>\n<p>Startup class&#8217;\u0131 ile, owin \u00fczerinden API&#8217;\u0131n host i\u015flemini ger\u00e7ekle\u015ftirece\u011fiz. Host i\u015flemi i\u00e7in &#8220;Program.cs&#8221; class&#8217;\u0131n\u0131 a\u015fa\u011f\u0131daki gibi g\u00fcncelleyelim.<\/p>\n<pre class=\"lang:c# decode:true \">using System;\r\nusing Microsoft.Owin.Hosting;\r\n\r\nnamespace CustomerApi.Host\r\n{\r\n    class Program\r\n    {\r\n        static void Main(string[] args)\r\n        {\r\n            using (WebApp.Start&lt;Startup&gt;(\"http:\/\/localhost:8090\"))\r\n            {\r\n                Console.WriteLine(\"Web Server is running.\");\r\n                Console.WriteLine(\"Press any key to quit.\");\r\n                Console.ReadLine();\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<p>&#8220;Microsoft.Owin.Hosting&#8221; namespace&#8217;i alt\u0131nda bulunan &#8220;WebApp&#8221; ile API&#8217;\u0131, localhost \u00fczerinden &#8220;8090&#8221; portu \u00fczerinden host edece\u011fiz. \u015eimdi s\u0131ra geldi controller&#8217;\u0131 eklemeye. Bunun i\u00e7in &#8220;Controllers&#8221; isminde yeni bir klas\u00f6r olu\u015fturup, &#8220;CustomerController.cs&#8221; class&#8217;\u0131n\u0131 i\u00e7erisine ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true \">using System.Web.Http;\r\nusing Contracts;\r\n\r\nnamespace CustomerApi.Host.Controllers\r\n{\r\n    [RoutePrefix(\"api\/customers\")]\r\n    public class CustomerController : ApiController\r\n    {\r\n        [HttpGet, Route(\"{id}\")]\r\n        public Customer Get(int id)\r\n        {\r\n            if (id &gt; 0)\r\n            {\r\n                return new Customer\r\n                {\r\n                    Id = 1,\r\n                    FullName = \"G\u00f6khan G\u00f6kalp\"\r\n                };\r\n            }\r\n\r\n            return null;\r\n        }\r\n    }\r\n}<\/pre>\n<p>Makale giri\u015finde de bahsetti\u011fimiz gibi art\u0131k &#8220;<em>api\/customers\/{id}<\/em>&#8221; URI&#8217;\u0131 ile, &#8220;0&#8221; dan b\u00fcy\u00fck bir id de\u011feri geldi\u011finde geriye &#8220;G\u00f6khan G\u00f6kalp&#8221; kullan\u0131c\u0131s\u0131n\u0131 d\u00f6necektir.<\/p>\n<p>Test edebilmek i\u00e7in &#8220;CustomerApi.Host&#8221; projesini \u00e7al\u0131\u015ft\u0131ral\u0131m ve &#8220;<em>http:\/\/localhost:8090\/api\/customers\/1<\/em>&#8221; URI&#8217;\u0131na bir GET request&#8217;inde bulunal\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/customer-response.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1054 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/customer-response.jpg\" alt=\"customer-response\" width=\"567\" height=\"379\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/customer-response.jpg 567w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/customer-response-300x201.jpg 300w\" data-sizes=\"(max-width: 567px) 100vw, 567px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 567px; --smush-placeholder-aspect-ratio: 567\/379;\" \/><\/a><\/p>\n<p>Yukar\u0131daki resimde oldu\u011fu gibi &#8220;1&#8221; numaral\u0131 id&#8217;ye sahip &#8220;G\u00f6khan G\u00f6kalp&#8221; kullan\u0131c\u0131s\u0131n\u0131n, response olarak geldi\u011fini g\u00f6r\u00fcyoruz.<\/p>\n<p>\u015eimdi &#8220;CustomerApi.Host&#8221; projesi i\u00e7in bir Unit Test projesi olu\u015fturaca\u011f\u0131z ve burada consumer&#8217;\u0131n olu\u015fturmu\u015f oldu\u011fu pact&#8217;lerin verify i\u015flemlerini ger\u00e7ekle\u015ftirece\u011fiz. &#8220;Service Provider&#8221; klas\u00f6r\u00fc i\u00e7erisine &#8220;CustomerApi.Tests&#8221; isminde yeni bir Unit Test projesi olu\u015ftural\u0131m ve projenin olu\u015fturma i\u015fleminin ard\u0131ndan Nuget Package Manager \u00fczerinden &#8220;xunit&#8221;, &#8220;xunit.runner.visualstudio&#8221; &#8220;PactNet&#8221; ve &#8220;Microsoft.Owin.Testing&#8221; paketlerini kural\u0131m. Paketlerin kurulum i\u015fleminin tamamlanmas\u0131ndan sonra &#8220;CustomerApi.Host&#8221; projesini de referans olarak ekleyelim.<\/p>\n<p>\u0130htiya\u00e7 duydu\u011fumuz paketler haz\u0131r oldu\u011funa g\u00f6re &#8220;CustomerTests.cs&#8221; isminde bir Unit Test class&#8217;\u0131 ekleyelim ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">using CustomerApi.Host;\r\nusing Microsoft.Owin.Testing;\r\nusing PactNet;\r\nusing Xunit;\r\n\r\nnamespace CustomerApi.Tests\r\n{\r\n    public class CustomerTests\r\n    {\r\n        [Fact]\r\n        public void EnsureCustomerApiHonoursPactWithConsumer()\r\n        {\r\n            \/\/Arrange\r\n            IPactVerifier pactVerifier = new PactVerifier(() =&gt; { }, () =&gt; { });\r\n\r\n            pactVerifier\r\n                .ProviderState(\"There is a customer with id 1\");\r\n\r\n            \/\/Act \/ Assert\r\n            using (var testServer = TestServer.Create&lt;Startup&gt;())\r\n            {\r\n                pactVerifier\r\n                .ServiceProvider(\"CustomerApi.Host\", testServer.HttpClient)\r\n                .HonoursPactWith(\"CustomerApiServiceConsumer\")\r\n                .PactUri(\"..\/..\/..\/CustomerApiServiceConsumer.Tests\/pacts\/customerapiserviceconsumer-customerapi.host.json\")\r\n                .Verify();\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<p>Burada olu\u015fturmu\u015f oldu\u011fumuz &#8220;EnsureCustomerApiHonoursPactWithConsumer&#8221; method&#8217;unun i\u00e7erisinde bir &#8220;PactVerifier&#8221; tan\u0131ml\u0131yoruz. Sonras\u0131nda ise verifier \u00fczerinden provider&#8217;\u0131n state&#8217;ini, &#8220;ServiceProvider()&#8221; fluent method&#8217;u ile hangi provider oldu\u011funu ve Owin TestServer&#8217;\u0131 \u00fczerinden gelen http client&#8217;\u0131n\u0131 parameter olarak set ediyoruz. &#8220;HonoursPactWith()&#8221; fluent method&#8217;u ile pact&#8217;i olu\u015fturan consumer&#8217;\u0131n name&#8217;ini ve &#8220;PactUri()&#8221; fluent method&#8217;u ile de olu\u015fturulmu\u015f olan pact&#8217;in URI adresini parametre olarak set ediyoruz.<\/p>\n<p>T\u00fcm parametrelerin set edilmesinden sonra &#8220;Verify()&#8221; method&#8217;unu \u00e7a\u011f\u0131rarak, provider&#8217;\u0131n mock test server&#8217;\u0131 \u00fczerinden consumer taraf\u0131ndan olu\u015fturulmu\u015f olan pact&#8217;lerin, verify i\u015fleminin ger\u00e7ekle\u015ftirilmesini sa\u011flam\u0131\u015f oluyoruz. T\u00fcm implementasyonumuz tamamlanm\u0131\u015f durumda. Hat\u0131rlarsak consumer taraf\u0131n\u0131 implemente ederken, test etmek ama\u00e7l\u0131 Unit Test case&#8217;ini \u00e7al\u0131\u015ft\u0131rm\u0131\u015ft\u0131k ve ba\u015far\u0131l\u0131 bir \u015fekilde pact file&#8217;\u0131 olu\u015fmu\u015ftu. \u015eimdi ise verify i\u015flemini deneyebilmek i\u00e7in gelin &#8220;EnsureCustomerApiHonoursPactWithConsumer&#8221; test case&#8217;ini \u00e7al\u0131\u015ft\u0131ral\u0131m ve sonucuna bir bakal\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/verify-test.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1056 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/verify-test.jpg\" alt=\"verify-test\" width=\"533\" height=\"222\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-test.jpg 533w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-test-300x125.jpg 300w\" data-sizes=\"(max-width: 533px) 100vw, 533px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 533px; --smush-placeholder-aspect-ratio: 533\/222;\" \/><\/a><\/p>\n<p>Evet bu test case&#8217;i de ba\u015far\u0131l\u0131 bir \u015fekilde sonu\u00e7land\u0131.<\/p>\n<p>Bu demek oluyor ki pact \u00fczerinde consumer&#8217;\u0131n provider&#8217;dan beklemi\u015f oldu\u011fu request ve response modelleri, mock test server&#8217;\u0131 \u00fczerinden \u00e7al\u0131\u015ft\u0131r\u0131larak ba\u015far\u0131l\u0131 bir \u015fekilde verify edildi. \u015eimdi gelelim ger\u00e7ek hayatta kar\u015f\u0131la\u015fabilece\u011fimiz bir problemi test etmeye. Diyelim ki Customer API m\u00fc\u015fteri detaylar\u0131n\u0131 art\u0131k &#8220;\/api\/customers\/1&#8221; \u015feklinde de\u011fil de, &#8220;\/api\/customers\/1\/detail&#8221; \u015feklinde veriyor olarak g\u00fcncellensin. Bunun i\u00e7in hemen ilgili controller&#8217;\u0131 a\u00e7arak a\u015fa\u011f\u0131daki gibi route&#8217;u g\u00fcncelleyelim.<\/p>\n<pre class=\"lang:c# decode:true \">using System.Web.Http;\r\nusing Contracts;\r\n\r\nnamespace CustomerApi.Host.Controllers\r\n{\r\n    [RoutePrefix(\"api\/customers\")]\r\n    public class CustomerController : ApiController\r\n    {\r\n        [HttpGet, Route(\"{id}\/detail\")]\r\n        public Customer Get(int id)\r\n        {\r\n            if (id &gt; 0)\r\n            {\r\n                return new Customer\r\n                {\r\n                    Id = 1,\r\n                    FullName = \"G\u00f6khan G\u00f6kalp\"\r\n                };\r\n            }\r\n\r\n            return null;\r\n        }\r\n    }\r\n}<\/pre>\n<p>Controller&#8217;\u0131 g\u00fcncelleme i\u015fleminden sonra solution&#8217;\u0131 derleyelim ve tekrardan &#8220;EnsureCustomerApiHonoursPactWithConsumer&#8221; test case&#8217;ini \u00e7al\u0131\u015ft\u0131ral\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/01\/verify-test-fail.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1057 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/01\/verify-test-fail.jpg\" alt=\"verify-test-fail\" width=\"535\" height=\"239\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-test-fail.jpg 535w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/01\/verify-test-fail-300x134.jpg 300w\" data-sizes=\"(max-width: 535px) 100vw, 535px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 535px; --smush-placeholder-aspect-ratio: 535\/239;\" \/><\/a><\/p>\n<p>Ups! Bu sefer test case&#8217;i ba\u015far\u0131l\u0131 bir \u015fekilde \u00e7al\u0131\u015ft\u0131r\u0131lamad\u0131. Hatan\u0131n detayl\u0131 a\u00e7\u0131klamas\u0131n\u0131 ise test case&#8217;inin bulundu\u011fu projenin klas\u00f6r\u00fc alt\u0131nda, &#8220;logs&#8221; isminde yeni bir klas\u00f6r olu\u015fturarak &#8220;providerName.host_verifier&#8221; isminde bir log dosyas\u0131 i\u00e7erisinde tutmaktad\u0131r.<\/p>\n<p>Bu case i\u00e7in PactNet&#8217;in olu\u015fturmu\u015f oldu\u011fu &#8220;customerapi.host_verifier.log&#8221; dosyas\u0131 ise a\u015fa\u011f\u0131daki gibidir.<\/p>\n<pre class=\"lang:default decode:true \">2017-01-21 18:04:21.080 +03:00 [Debug] Verifying a Pact between CustomerApiServiceConsumer and CustomerApi.Host\r\n  Given There is a customer with id 1\r\n    A GET request to retrieve the customer\r\n      with GET \/api\/customers\/1\r\n        returns a response which\r\n          has status code 200\r\n          includes headers\r\n            'Content-Type' with value application\/json; charset=utf-8\r\n          has a matching body\r\n2017-01-21 18:10:47.502 +03:00 [Debug] Verifying a Pact between CustomerApiServiceConsumer and CustomerApi.Host\r\n  Given There is a customer with id 1\r\n    A GET request to retrieve the customer\r\n      with GET \/api\/customers\/1\r\n        returns a response which\r\n          has status code 200 (FAILED - 1)\r\n          includes headers\r\n            'Content-Type' with value application\/json; charset=utf-8\r\n          has a matching body (FAILED - 2)\r\n\r\nFailures:\r\n\r\n1) Expected: 200, Actual: 404\r\n\r\n2) Expected: {\r\n  \"Id\": 1,\r\n  \"FullName\": \"G\u00f6khan G\u00f6kalp\"\r\n}, Actual: {\r\n  \"Message\": \"No HTTP resource was found that matches the request URI 'http:\/\/localhost\/api\/customers\/1'.\"\r\n}\r\n<\/pre>\n<p>Yukar\u0131daki log sat\u0131rlar\u0131 asl\u0131nda gayet anla\u015f\u0131l\u0131r bir \u015fekilde a\u00e7\u0131k. PactNet burada, consumer&#8217;\u0131n ne istedi\u011fi ve ne bekledi\u011fini provider taraf\u0131ndan sa\u011flamaya \u00e7al\u0131\u015f\u0131yor. &#8220;Failures&#8221; alt\u0131nda ise HTTP status&#8217;\u00fc olarak &#8220;200&#8221; bekledi\u011fini ancak &#8220;404&#8221; ald\u0131\u011f\u0131n\u0131 ve &#8220;1&#8221; numaral\u0131 m\u00fc\u015fteriye ait bilgileri almas\u0131 gerekirken, &#8220;No HTTP resource was found&#8230;&#8221; \u015feklinde bir hata mesaj\u0131 ile kar\u015f\u0131la\u015ft\u0131\u011f\u0131n\u0131 s\u00f6yl\u00fcyor. Ne kadar harika de\u011fil mi?<\/p>\n<p>Consumer Driven Contract Testing bize, de\u011fi\u015fen ihtiya\u00e7lar kar\u015f\u0131s\u0131nda deployment yapmadan \u00f6nce nerelerin etkilenebilece\u011fini h\u0131zl\u0131 bir \u015fekilde ula\u015fabilmemizi sa\u011flamaktad\u0131r. \u00d6zellikle microservice yap\u0131lar\u0131n\u0131n bulundu\u011fu ortamlarda, nerelerin etkilenebilece\u011fi tarz concern&#8217;lerin giderilebilmesi i\u00e7in kullan\u0131lmas\u0131 gerekmektedir diye d\u00fc\u015f\u00fcn\u00fcyorum son zamanlarda. Bunlara ek olarak birde az \u00f6nce &#8220;PactUri()&#8221; fluent method&#8217;u ile consumer&#8217;\u0131n olu\u015fturmu\u015f oldu\u011fu pact&#8217;in adresini set etmi\u015ftik. Bu pact&#8217;leri dilersek network \u00fczerinde ortak bir yerde de persist ederek, verify i\u015flemini oradan ger\u00e7ekle\u015ftirebilmek de m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<p>Umar\u0131m yararl\u0131 ve keyifli bir makale olmu\u015ftur. Makale s\u0131ras\u0131nda ger\u00e7ekle\u015ftirmi\u015f oldu\u011fumuz \u00f6rnek projeye, a\u015fa\u011f\u0131daki github hesab\u0131m \u00fczerinden eri\u015febilirsiniz.<\/p>\n<p><a href=\"https:\/\/github.com\/GokGokalp\/consumer-driven-contracts-testing-sample\" target=\"_blank\">https:\/\/github.com\/GokGokalp\/consumer-driven-contracts-testing-sample<\/a><\/p>\n<p>Kaynaklar:<\/p>\n<blockquote><p>https:\/\/github.com\/SEEK-Jobs\/pact-net<br \/>\nhttps:\/\/martinfowler.com\/articles\/consumerDrivenContracts.html<br \/>\nhttps:\/\/tech.affinitas.de\/?p=51<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Merhaba arkada\u015flar. Yine microservice mimarilerine y\u00f6nelik bir konu ile kar\u015f\u0131n\u0131zday\u0131m. Sizlerde biliyorsunuz ki son d\u00f6nemlerde neredeyse t\u00fcm ilgi alan\u0131m\u0131, microservice\u00a0mimarileri ve MQ(Message Queue) tabanl\u0131 sistemlere yo\u011funla\u015ft\u0131rd\u0131m. Bu sistemler her ne kadar bir \u00e7ok derdimizi \u00e7\u00f6zseler bile, asla kusursuz bir \u015fey olmad\u0131\u011f\u0131 gibi beraberlerinde getirdi\u011fi baz\u0131&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,48,368,178],"tags":[367,361,365,364,358,359,363,366,360,362],"class_list":["post-1034","post","type-post","status-publish","format-standard","hentry","category-net","category-asp-net-web-api","category-microservices","category-test-driven-development","tag-api-integration-test","tag-api-test","tag-c-pact","tag-c-pact-kullanimi","tag-consumer-driven-contract","tag-consumer-driven-contract-test","tag-contract-test","tag-microservice-integration-test","tag-microservice-test","tag-web-api-test","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":false,"content":false,"excerpt":false}}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/\" \/>\n<meta property=\"og:site_name\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"article:published_time\" content=\"2017-01-21T17:40:11+00:00\" \/>\n<meta name=\"author\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/\"},\"author\":{\"name\":\"G\u00f6khan G\u00f6kalp\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"headline\":\"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon\",\"datePublished\":\"2017-01-21T17:40:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/\"},\"wordCount\":2674,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"keywords\":[\"api integration test\",\"api test\",\"c# pact\",\"c# pact kullan\u0131m\u0131\",\"consumer driven contract\",\"consumer driven contract test\",\"contract test\",\"microservice integration test\",\"microservice test\",\"web api test\"],\"articleSection\":[\".NET\",\"Asp.Net Web API\",\"Microservices\",\"Test Driven Development\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/\",\"name\":\"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\"},\"datePublished\":\"2017-01-21T17:40:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"description\":\"C# &amp; Python lover\",\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gokhan-gokalp.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"pronouns\":\"he\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"caption\":\"G\u00f6khan G\u00f6kalp\"},\"logo\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\"},\"sameAs\":[\"https:\\\/\\\/gokhan-gokalp.com\"],\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/tr\\\/author\\\/gok-gokalp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/","og_locale":"tr_TR","og_type":"article","og_title":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp","og_url":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/","og_site_name":"G\u00f6khan G\u00f6kalp","article_published_time":"2017-01-21T17:40:11+00:00","author":"G\u00f6khan G\u00f6kalp","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"G\u00f6khan G\u00f6kalp","Tahmini okuma s\u00fcresi":"16 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/#article","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/"},"author":{"name":"G\u00f6khan G\u00f6kalp","@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"headline":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon","datePublished":"2017-01-21T17:40:11+00:00","mainEntityOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/"},"wordCount":2674,"commentCount":4,"publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"keywords":["api integration test","api test","c# pact","c# pact kullan\u0131m\u0131","consumer driven contract","consumer driven contract test","contract test","microservice integration test","microservice test","web api test"],"articleSection":[".NET","Asp.Net Web API","Microservices","Test Driven Development"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/","url":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/","name":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon - G\u00f6khan G\u00f6kalp","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/#website"},"datePublished":"2017-01-21T17:40:11+00:00","breadcrumb":{"@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/gokhan-gokalp.com\/microservice-mimarilerinde-consumer-driven-contracts-testing-nedir-c-sharp-ile-implementasyon\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gokhan-gokalp.com\/"},{"@type":"ListItem","position":2,"name":"Microservice Mimarilerinde Consumer Driven Contracts Testing Nedir? ve C# ile Implementasyon"}]},{"@type":"WebSite","@id":"https:\/\/gokhan-gokalp.com\/#website","url":"https:\/\/gokhan-gokalp.com\/","name":"G\u00f6khan G\u00f6kalp","description":"C# &amp; Python lover","publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gokhan-gokalp.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe","name":"G\u00f6khan G\u00f6kalp","pronouns":"he","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","url":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","caption":"G\u00f6khan G\u00f6kalp"},"logo":{"@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659"},"sameAs":["https:\/\/gokhan-gokalp.com"],"url":"https:\/\/gokhan-gokalp.com\/tr\/author\/gok-gokalp\/"}]}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1034","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=1034"}],"version-history":[{"count":17,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1034\/revisions"}],"predecessor-version":[{"id":1059,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1034\/revisions\/1059"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=1034"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=1034"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=1034"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}