Consumer Driven Contract Testing Node.js with Pact – Peter Czibik – NodeBP 2018



our second speaker is Peter Civic from rising stack and he's going to talk about consumer-driven contract testing and nodejs yeah okay very serious topic quite long it has a subtitle which is verification across service boundaries which is again long and I have a sub subtitle and that is how to reliably ship code the multiple teams are working on multiple parts of a single product even longer you're going to know what this means in a few minutes first a few things about me all those technologies that I really like I consider myself a nerd in general I'm a senior node.js developer Linux enthusiast lover of programming why am I reading this is me I mean and I'm generally a nice guy so if you'd like to grab a beer talk about something that's on the on the slides or something else maybe grab a beer today we are going to on care right so we have reservation let's get into it so first I'm working at rising stack I'm senior nodejs developer consultant and we have companies succeed with micro services who here works with micro services raise your hands yay there are a couple of hands micro services basically when you try to ship single application in multiple parts because probably multiple people are involved and then and and the general approach to micro services looks kind of like this it's not simple we have for example look at that guy with the blender over there he is responsibility is only pushing one button right I mean how high can it be you just push the button blender opens some things fall into it and then it it just integrates with other parts but this is the part where we what we are currently currently I'm going to talk about is how you can make sure that your interfaces which in this case this guy has two interfaces or actually three one that falls into it and the the second the the the other two are the the moving parts on the other side so consider that as our example right now I have a story to tell and it is a story not not mine but someone working at Atlassian probably you know them from JIRA they're super amazing project management service right I mean everyone loves it too independent services they had payment and users and they noticed that something is wrong in payment and you get an alert you wake up in the middle of the night and then you see that something is not quite right there was somebody in the users working well both of the services were independently deployed they were micro services in the whole architecture in less payment in the users people who were working on the on the user service they changed a single letter in the JSON response I mean they wanted to do not do good to do good I mean those people they just wanted to make it look right it's an array it should be users right but the problem is that it breaks some other stuff in in the whole architecture and there's actually no worse thing than not letting your users pay you want their money right I mean why not how can we avoid problems like that we have to write tests many and many many many many different kind of tests if you go back to our microservices example everyone loves this gift so as much time we can look at it as a better but I mean we have to write tests because there are so many layers of this this small blender guy let's let's go back we have to test that the button button is is working right the lid opens and the the small blue things fall into the right place right but what kind of tests you may ask this is a test fire I mean you if you're not yet familiar it describes how so there are different kinds of tests you see there are unit tests integration tests an end-to-end test the test item it describes how many of them we should write based on based on these things over here unit tests are super cheap to write and they are fast to run so if you have a unit test those are in the JavaScript world generally are like marker type tests that you have and then you mix expectations and then your code runs and it's file integration tests or your making sure that the whole system works as intended and your endpoints are working and stuff like that end-to-end test or like the UI test step that we have in place that you know there's a robot kind of AI super intelligent thing that presses some buttons and then things happen and then you observe the side effects this is a this is a pirate me that we have here UI tests are slow to run and really expensive to run because you have to have a browser kind of thing and you have to have instances of those and services available for DUI to call but these things are not enough that's what I'm saying we need to go deeper we have to test actually beyond borders not just in level when we're talking about micro service architectures we are talking about things well not only micro service this applies to client-server architectures as well because when we are working on clients for example these are deployed separately to our servers cuz these are like super react applications that are written in yes 2000 something something and then we have separate code bases we want to deploy the UI team wants to deploy separately because they want to change the CSS the back-end team wants to change we want to deploy it separately because they want to change an S in the response zone where they both have individual deployments and then they are written in multiple languages so it's quite hard to to start the testing beyond borders and as I've talked already about this applies to server-to-server communication for example in a micro service architecture or server client communication – and these concepts that I'm going to talk about will apply to both worlds I have solution a for texting Beyond Borders mocking a programmer typically creates a mock object attach the behavior of some other object in much the same way that the core designer uses a crash-test dummy to simulate the behavior of a human so when we talk about mock objects they are usually some kind of fake objects that we create just for a single test case mock so when we are talking about testing Beyond Borders so like inter-service communication one service calling HTTP endpoint one and then with mocking what we can do we can maybe use a library that we usually use called knock and Ock it creates HTTP mock objects and it is really light on resources it it creates no data pollution meaning that it's not going to call a production service and create like user entities or something like that in the database and it's pairs maintenance cost because you don't have to maintain actually anything I points out issues quickly you can see that this test failed at this part and then it's idempotent means that if we call it multiple times it's going to return the same data or at least it should it's not trustworthy by trustworthy I mean when we're talking about integration points usually the team that's that is creating test for service a will create the mocks for service B to test service a hope it makes sense but when when somebody creating test they are going to go to the documentation of the service B and and then read that and based on that creates a mock data mock objects that that they are going to use and that's not trustworthy because it's not actually calling something in there it's not actually running actual code written by a human or some supercomputer but it's going to call itself and there's another solution what we can use is we can use an instance of an upstream service when we're talking about the containers and stuff like that we can think of an instance of an upstream services like a docker container provided by the other team I'm working on on service a and I want a test service B I asked some DevOps engineer from service B and please give me your docker container so I can use it in a test and then before your tests are getting on you docker start something but you know that's kind of hard to use other teams code without actually knowing and without actual like super long documentation and it's it's trustworthy it's the same thing I've talked about before is that if actual code is getting run and you're calling actual an actual dr. container running the code that is going to be run in production you can trust it it's going to return the same data if it's the same container but it's expensive you know it has costs that you might not even consider you have to learn how these things work you have to learn how to spin up their service it might require Kinect Postgres connection rabbitmq ready is this and that and they might not have prepared their service for just running it in test mode it's non idempotent meaning that multiple costs the same service can return some kind of maybe stale data or data that's not like up-to-date so it's it's really up to the people who are implementing the service to make it either important but it's not sometimes it's just not the case these are usually those tests that you have to run five or six times to make it pass you know we've never done that right to wrap it up we have mocking and we have an extra instance one of them is idempotent the other is not one of them is light on resources the other one is resource heavy cheap but we have to consider its trustworthiness to balance between the two and these are totally legit test cases I mean test methodologies for testing Beyond Borders so if you're using these these things in product to test your production systems it's totally fine but I have a solution C and then C is for contract and contract testing is what I'm what I'd like to tell you about is that it has so it I have a slide over here let's see this contract testing fits somewhere in between or covers both parts of the test pyramid of integration test an end-to-end test so if you'd like to position this part somewhere in the pyramid it's right there we go back we have contractors again and by contract we are defining an interface between as I talked about service a and service B and what the contract is it's just an interface it describes an interface that I'm going to return this JSON for this request and then both parties will use this this contract this interface to test and contract testing will use real data has no extra infrastructure cost because we're going to see how it fits into our current testing pipeline and it does not require you to to spin up a new service to write well you will have to write some extra code but it has no extra infrastructure cost and it's fast with occasional synchronization in between the server and the client and it is really easy to scale because anyone we're going to see how but you can pull down these contracts from a central repository and then anyone can test against it and if his quick set-up time so it's it doesn't require a bunch of extra code and it is very stable you can expect the same results as you as we've talked about with idempotency and reliability and again it fits somewhere in the UI and the service layer and then there is to contract testing contract testing itself as it probably has multiple implementations but none of them is is really well spread so a consumer-driven contract I think is the thing that we are going to talk about I'm going to show you and it has implementation steps as the client so we're talking about server and client or server or server communication we have service a and then we have service B I'm going to call service a our client because that is that is the one that's going to consume some resources of service B the client service a makes X fixed expectations I want for this query I want some data I want this set of data to be returned and then the client itself within its it's a test pipeline uses these expectations to test and then we serialize these expectations to language-independent format we take these expectations transfer it to a central repository and then the server can pull this expectations down and then the server then you will use these expectations to test itself this is the flow of a consumer-driven contract testing pipeline and there's a library that implements most so you can implement this yourself you can create a set of expectations and then these can be also in JavaScript I mean all homebrew solutions are fine we are I'm not currently advocating for this library what I'm advocating for is is when you were working in a scenario that there's a client and the server communication or server-to-server communication you want to test beyond borders you want to test integration parts from one to another how you're doing it is it doesn't really matter but there's a library that already handles a bunch of things for us it's called pact they have a nice website and the logo so it's probably a good project right that's how it works so pact is an implementation of a consumer-driven contract testing and it uses JSON as that serialization layer so it's it's really language independent you can consume JSON in any and kind of language and currently there are libraries already out there for multiple languages like Dartmouth and JVM and JavaScript I know there's Rost in the making so bunch of others so I have I have a small demo I don't want to run the demo and you I have instructions for you guys if you want to ever run the demo yourself but I know I've done so many demos already and all of them just failed so I'm just going to look I'm just going to show you some code oh we're not winning yeah I'm just gonna show you some some code that I have here what you need to actually implement all of these things and it's going to be in nodejs Wow amazing so what we have here is we have a client and you're probably already familiar with a request module it's a wrapper for HTTP requests and what we're doing here is we're we're making an HTTP request to give an URL to receive a prod we give some products it is gray I pre checked it man I mean I went there so it's even visible from our office fancy actor yeah I mean so we're making a request with a query and then we're saying this is a JSON request it doesn't really matter what really matters is we create expectations here and with these expectations that we have that for products with a given query it should it will respond with and there's there are some helper methods on this packed matchers like this object should look something like you know we're all used to this we don't want to exactly define IDs or something like that so we have all these helper methods to for us to use so for this request that is like the product that has this query it will respond with 200 and each of the products should look something like this static JSON that we have over here then we have these expectations and we transfer it to a repository that's what packed gives you it gives you a docker container that you can run and then configure your stuff to settle it over to that docker container and it's going to save it in in its database and everything's gonna be fine and you you just put all those things to your your server and then you use that in the server part to test everything and this is the server consumer test and you there's actually some extra set up that you can do for example creating you see you creating fake products it has one product this was something that we have described here in the interactions part it has one product this is a state so we are even describing what stay or server or provide because this is has these term pact and most of other libraries has this term its provider which is a server and consumer which is a client and then we have we can describe state and then this service should there's a test setup and the state should be one product so we create a product and then what we do is we verify the pacts and and we get on with our lives with and we can run these tests so we have all these tests to run in our in our CI pipeline and every time so a client will make new expectations right and next time or server service that will be deployed you know if we go back to our example of Atlassian if someone changes an S in the JSON response in the in the server or or the provider they run the test against the against the packed JSON thing then they are going to be instantly notified that hey you might you should just reconsider this deployment let's just revert that you and then you compare this with other tools like blue-green deployments and maybe let some you know if these if these expectation paths then then you might integrate it into your existing testing and verification pipeline so there are a bunch of things you can do with it and I'm not saying that act is the only way to do this I'm saying that if you are working in a scenario which involves multiple parties multiple teams working together you should make sure that you never ever break your clients code and then it's going to be a win-win situation for everyone thank you for your attention and if you have any questions please ask them right now or maybe Fatih is around so you can pass you that yeah thank you here anyone has questions maybe great yes so am I right to assume that basically what you're advocating for is like something similar to BDD like behavior testing well well you have a scenario that the users described and then basically a DSL mm-hm and then then you implement a DSL yes but not just within within the boundaries of a single server context but also it's like in between multiple services so yeah that's basically an implementation of that and a good one anyone else maybe so my question is have you ever done this kind of testing across companies in which one company is asking and using I have not personally deployed it to any scenario like that but I don't see how it could not work so the only thing that you that pact might not give you is some authentication layer does it give you a sonication by the way no it doesn't so then you would probably have to set up some kind of internal network between the two companies and that might be something that might cause some security issues in but we have successfully used it in between teams and I've seen it working between some teams that were working individually so I am I don't see any problem making this working between multiple companies just one more question if as I understand all you have to do is upload to a repository from server and just shared that positive each only has contracts and that's so if both companies access that repository that's thank you yes they have a docker container I even have some okay so if you use their pact container it actually gives you a nice little UI UI as well so you're gonna be able to browse the uploaded packs and see if they are verified by the clients in which client verified it which didn't what you failed and so forth well actually what you said is is right it's only that you lose the UI and we have this this is this repository is public by the way it's rising stack so on github rising stack pact example let me show you really quickly and yay so this is the one it's public you can check it out it has all the code I don't claim Fame for this one this was all written by the fine gentleman sitting over there but but I mean it's good in the package.json there are some some jobs that like docker run and then we have this broker example over there that like handles it's just a docker container you have to run give it the URL and it will shop the JSON in there so other teams can pull it down they made it pretty easy to work with this one and and you should start at least give it a go and if you like they are looking for contributors they have their issues marked as good first contribution so there are generally nice people too yeah I got a question that do this sir server developers also write their packets or just appliance it's just the client and the server uses that to verify if the server has if the server is also a client you know it can happen if it might call back or might cause some others then they will have to write their own back stuff so if I am server and I don't know Lyons they all right there I know each of the clients so if you have ten clients that means that you will have to be verified against ten clients as a server if you are a client that connects to ten servers then you will have to write ten of these back tests so do clients independently write their own facts basically yes so it has to implement their own that is hence the name consumer-driven so consumer is really client here and then wait a minute because your mock and the server all the time in all the ten consumers right you're doing the exact same thing here it's only the mocks themselves that create the pads so a mark itself is already a contract right that has to be fulfilled and you just share this contract with the server and in the mock you sign and calling this I'm gonna get this answer right so practically a pack is gonna call the producer the server based on that walk and we'll chat it got the answer that the consumer expected right so it's not really an overhead in that sense because you already these marks anyway well they are on the back broker server so they're a unified and a repository then I'm not sure about if if you like share so if you share the same test in between clients right that's what you're asking I'm not sure if you can do that can you I mean that's anyone but that's or at least I've only seen the implementation part on server pulling that down but not client pulling that down yeah the clients should know yeah the client should not so you have to like implement in multiple times or at least as far as I know you have to do that there might be some it's something hidden in the documentation or if you're up to that you know we can create an issue we can also implement it in another session but not today probably okay anyone else maybe one last question no okay let's continue eating on care I think so thanks Peter for your amazing talk I think having me yeah thanks everyone for showing up for the next time we will order more beer and more peds I promise so variable

2 thoughts on “Consumer Driven Contract Testing Node.js with Pact – Peter Czibik – NodeBP 2018

Leave a Reply

Your email address will not be published. Required fields are marked *