|
| 1 | +@page "/blog/contract-testing-in-pact-with-events" |
| 2 | +@using TestArena.Blog.Common |
| 3 | + |
| 4 | +<BlogContainer> |
| 5 | + <Header |
| 6 | + Title="Intro to PACT for .NET Core: Events Based Systems" |
| 7 | + ImageUrl="/images/blog/pact/intro-to-pact.jpg" |
| 8 | + PublishDate="2024-06-24" |
| 9 | + Authors="Ajay Kumar" /> |
| 10 | + |
| 11 | +<Header |
| 12 | + Title="Intro to PACT for .NET Core: Events Based Systems" |
| 13 | + ImageUrl="/images/blog/pact/intro-to-pact.jpg" |
| 14 | + PublishDate="2024-06-24" |
| 15 | + Authors="Ajay Kumar" /> |
| 16 | + |
| 17 | +<Section Heading="Introduction"> |
| 18 | + <p>This is a continuation of the PACT for .NET series where I am going to cover the usage of PACT in event-based systems.</p> |
| 19 | + <p>This article assumes the readers will have a basic understanding of event-based systems and frameworks. In case not, a good place to start can be <a href="https://www.rabbitmq.com/tutorials">RabbitMQ Tutorials</a>.</p> |
| 20 | + <p>I will be using the same repo setup that I have used to demonstrate usage in API-based systems. I have covered the setup in detail in a previous blog in this series:</p> |
| 21 | + <p><a href="/blog/contract-testing-pact-net-intro">Contract testing for APIs: Intro to PACT for .NET Core</a></p> |
| 22 | +</Section> |
| 23 | + |
| 24 | +<Section Heading="Scenario: Event Flow" Level="5"> |
| 25 | + <p>For illustration purposes, we can imagine a scenario where the Result service (Consumer) wants to get informed whenever a student is created.</p> |
| 26 | + <BlogImage ImagePath="/images/blog/pact/events-demo/Publisher-Broker-Listener.webp" Description="Publisher/Broker/Listener Diagram" Number="1"/> |
| 27 | + <p>Now since both Result and Student are separate services, below is the infrastructure that has been implemented in order to make that work.</p> |
| 28 | + <p>I have incorporated the RabbitMQ library as a messaging service in both the APIs.</p> |
| 29 | +</Section> |
| 30 | + |
| 31 | +<Section Heading="Publishing Events" Level="5"> |
| 32 | + <p>Whenever a new student is created using the Student service’s (Provider) POST API, we are publishing an event called <strong>StudentCreatedEvent</strong>.</p> |
| 33 | + <GithubGistSnippet Title="Publish event during student creation" UserId="ajaysskumar" FileName="513f17acb18ec1b6029e4850f8bc2683" /> |
| 34 | + |
| 35 | + <p>The event structure includes details such as:</p> |
| 36 | + <GithubGistSnippet Title="Properties inside StudentCreatedEvent" UserId="ajaysskumar" FileName="24a64b48634f478bc0d617ff83108565" /> |
| 37 | +</Section> |
| 38 | + |
| 39 | +<Section Heading="Listening to Events" Level="5"> |
| 40 | + <p>Now the above event can be listened to by any service interested in that event. In this scenario, that service is the Result service.</p> |
| 41 | + |
| 42 | + <p>There is a listener defined in the Result service which may perform any operation based on the information received in the <strong>StudentCreatedEvent</strong>.</p> |
| 43 | + |
| 44 | + <GithubGistSnippet Title="Student created event listener in Result service" UserId="ajaysskumar" FileName="5265e3d73d242bbdecc0b162fd4ba4b9" /> |
| 45 | + |
| 46 | + <p>For example, it may store student details in the Result service to avoid direct dependency on the Student service while preparing results.</p> |
| 47 | + <BlogImage Src="/images/blog/pact/student-event-listener.jpg" Alt="Student created event listener in Result service" /> |
| 48 | +</Section> |
| 49 | + |
| 50 | +<Section Heading="Contract Testing with PACT" Level="4"> |
| 51 | + <p>The first part of contract testing involves defining the expected event structure on the consumer side, which results in generating a PACT JSON contract file.</p> |
| 52 | + |
| 53 | + <GithubGistSnippet Title="Consumer test defining the contract" UserId="ajaysskumar" FileName="ddbb5a5ffb05223d785146f2baaf9f94" /> |
| 54 | + |
| 55 | + <p>Once the contract is defined, a PACT JSON contract file is generated, which looks something like this:</p> |
| 56 | + |
| 57 | + <GithubGistSnippet Title="Contract snapshot" UserId="ajaysskumar" FileName="fef0bbd541154a7ce8debd5964a54ca6" /> |
| 58 | +</Section> |
| 59 | + |
| 60 | +<Section Heading="Verifying the Provider" Level="4"> |
| 61 | + <p>Now that this contract file has been created, we need to write tests on the provider side to ensure that it adheres to the contract.</p> |
| 62 | + <GithubGistSnippet Title="Provider side contract verification" UserId="ajaysskumar" FileName="d7f58cef45c94f59b295b12d3dee2852" /> |
| 63 | + |
| 64 | +</Section> |
| 65 | + |
| 66 | +<Section Heading="PACT Testing in Action" Level="4"> |
| 67 | + <p>Now that this setup is ready, we can quickly do a build and test:</p> |
| 68 | + <span><code>dotnet build</code></span> <br/> |
| 69 | + <span><code>dotnet build</code></span> <br/> |
| 70 | + <p>Alternatively, you can run individual tests as well.</p> |
| 71 | + <BlogImage ImagePath="/images/blog/pact/events-demo/success test.webp" Description="Success test" Number="2"/> |
| 72 | +</Section> |
| 73 | + |
| 74 | +<Section Heading="Failure Case Example" Level="4"> |
| 75 | + <p>To test a failure case, we can make some changes in our provider. For example, renaming the <strong>LastName</strong> field to <strong>LName</strong> and rerunning the tests.</p> |
| 76 | + |
| 77 | + <GithubGistSnippet Title="LastName property renamed to LName" UserId="ajaysskumar" FileName="a85b14d4d16831e181ba7551aa69bdfa" /> |
| 78 | + |
| 79 | + <p>When we run the tests, we can see the results:</p> |
| 80 | + |
| 81 | + <BlogImage ImagePath="/images/blog/pact/events-demo/Provider tests hinting at the actual gap between consumer and provider contract.webp" Description="Provider tests hinting at the actual gap between consumer and provider contract" Number="3" /> |
| 82 | + |
| 83 | + <p>As we see in the results above, the error message suggests that the <strong>LastName</strong> field is missing on the provider side.</p> |
| 84 | +</Section> |
| 85 | + |
| 86 | +<Section Heading="Conclusion" Level="4"> |
| 87 | + <p>By implementing contract testing with PACT for event-based systems, we ensure reliable integrations between services.</p> |
| 88 | + <p>This methodology helps detect issues early, ensuring both consumer and provider remain in sync.</p> |
| 89 | + <p>For reference, the code repository being discussed is available on <a href="https://github.com/ajaysskumar/pact-net-example">GitHub</a>.</p> |
| 90 | + <p>Thanks for reading! Please share feedback in the comments or reach out via email at <a href="mailto:ajay.a338@gmail.com">ajay.a338@gmail.com</a>.</p> |
| 91 | +</Section> |
| 92 | + |
| 93 | + |
| 94 | +</BlogContainer> |
0 commit comments