1"use strict";(self.webpackChunkpartners=self.webpackChunkpartners||[]).push([[9329],{15680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var i=r(96540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?n(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):n(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,i,o=function(e,t){if(null==e)return{};var r,i,o={},n=Object.keys(e);for(i=0;i<n.length;i++)r=n[i],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(i=0;i<n.length;i++)r=n[i],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=i.createContext({}),p=function(e){var t=i.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},c=function(e){var t=p(e.components);return i.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},g=i.forwardRef((function(e,t){var r=e.components,o=e.mdxType,n=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(r),g=o,y=d["".concat(l,".").concat(g)]||d[g]||u[g]||n;return r?i.createElement(y,a(a({ref:t},c),{},{components:r})):i.createElement(y,a({ref:t},c))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var n=r.length,a=new Array(n);a[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:o,a[1]=s;for(var p=2;p<n;p++)a[p]=r[p];return i.createElement.apply(null,a)}return i.createElement.apply(null,r)}g.displayName="MDXCreateElement"},28390:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>n,metadata:()=>s,toc:()=>p});var i=r(58168),o=(r(96540),r(15680));const n={title:"Provider Testing Guide",sidebar_label:"Provider"},a=void 0,s={unversionedId:"docs/bi-directional-contract-testing/provider",id:"docs/bi-directional-contract-testing/provider",title:"Provider Testing Guide",description:"Principles",source:"@site/docs/docs/bi-directional-contract-testing/provider.md",sourceDirName:"docs/bi-directional-contract-testing",slug:"/docs/bi-directional-contract-testing/provider",permalink:"/docs/bi-directional-contract-testing/provider",draft:!1,editUrl:"https://github.com/pactflow/docs.pactflow.io/edit/master/website/docs/docs/bi-directional-contract-testing/provider.md",tags:[],version:"current",lastUpdatedBy:"Michael Kressibucher",lastUpdatedAt:1741595885,formattedLastUpdatedAt:"Mar 10, 2025",frontMatter:{title:"Provider Testing Guide",sidebar_label:"Provider"},sidebar:"docs",previous:{title:"Consumer",permalink:"/docs/bi-directional-contract-testing/consumer"},next:{title:"Publishing Contracts",permalink:"/docs/bi-directional-contract-testing/publishing"}},l={},p=[{value:"Principles",id:"principles",level:2},{value:"Writing Provider Contracts",id:"writing-provider-contracts",level:2},{value:"Step 1: Authoring or generating your OpenAPI Specification",id:"step-1-authoring-or-generating-your-openapi-specification",level:3},{value:"Step 2: Choose an API testing tool",id:"step-2-choose-an-api-testing-tool",level:3},{value:"Step 3: Verifying the Provider Contract (Testing your API)",id:"step-3-verifying-the-provider-contract-testing-your-api",level:3},{value:"Step 4: Publish your Provider Contract and verification results",id:"step-4-publish-your-provider-contract-and-verification-results",level:3},{value:"Step 4: Run can-i-deploy",id:"step-4-run-can-i-deploy",level:3},{value:"Step 5: Deploy your application",id:"step-5-deploy-your-application",level:3},{value:"Integrating it into your CI/CD pipeline",id:"integrating-it-into-your-cicd-pipeline",level:2},{value:"Other",id:"other",level:2},{value:"Other examples of how to do this form of testing",id:"other-examples-of-how-to-do-this-form-of-testing",level:3}],c={toc:p},d="wrapper";
1function u(e){let{components:t,...n}=e;return(0,o.yg)(d,(0,i.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h2",{id:"principles"},"Principles"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},"Testing the provider API is your responsibility. PactFlow simply ensures the specification is compatible with any consumers"),(0,o.yg)("li",{parentName:"ul"},"Garbage in, Garbage out - PactFlow trusts any provider contract provided. This is true, whether it has been tested or not."),(0,o.yg)("li",{parentName:"ul"},"When using the BYO functional API testing strategy, you must ensure your API is compatible with (and ideally, implements) any specification."),(0,o.yg)("li",{parentName:"ul"},"Code-based approaches are generally preferred because they are less likely to drift from implementation. For example, using tools that generate OAS definitions from code/types is more reliable"),(0,o.yg)("li",{parentName:"ul"},"When supported, test-based approaches such as ReadyAPI Functional test suites/postman collections, may also be more reliable, as they have embedded testing information in them. Uploading only the tested parts of the provider contract to PactFlow improves the guarantees we can provide.")),(0,o.yg)("h2",{id:"writing-provider-contracts"},"Writing Provider Contracts"),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"Provider Test",src:r(6738).A,title:"Provider Test",width:"2560",height:"1440"})),(0,o.yg)("h3",{id:"step-1-authoring-or-generating-your-openapi-specification"},"Step 1: Authoring or generating your OpenAPI Specification"),(0,o.yg)("p",null,"You must have, or be able to produce, one of the following OpenAPI Specification (OAS) formats:"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},"OAS v2.0"),(0,o.yg)("li",{parentName:"ul"},"OAS v3.0.x"),(0,o.yg)("li",{parentName:"ul"},"OAS v3.1.x")),(0,o.yg)("p",null,"If you don't have an OAS, you can convert from a format you already have or from your code (e.g. via types/annotations) before uploading to Pact."),(0,o.yg)("p",null,"For example, there are tools that convert Postman collections or RAML documents to OAS."),(0,o.yg)("h3",{id:"step-2-choose-an-api-testing-tool"},"Step 2: Choose an API testing tool"),(0,o.yg)("p",null,"There are many tools available. You may want to choose a black-box style functional API testing tool like ReadyAPI/SoapUI/Dredd or Postman, or white-box style tools such as RestAssured or Supertest."),(0,o.yg)("p",null,"The key consideration is ensuring your API is compatible with an OAS."),(0,o.yg)("h3",{id:"step-3-verifying-the-provider-contract-testing-your-api"},"Step 3: Verifying the Provider Contract (Testing your API)"),(0,o.yg)("p",null,"Configure your CI pipeline to run these tests on every change. We suggest running these tests against a locally running server so that you have control and therefore determinism in your tests."),(0,o.yg)("p",null,"Running against a dedicated testing environment will likely result in flaky tests."),(0,o.yg)("h3",{id:"step-4-publish-your-provider-contract-and-verification-results"},"Step 4: Publish your Provider Contract and verification results"),(0,o.yg)("p",null,"After your tests have completed (pass/fail), you should upload the specification and results to PactFlow."),(0,o.yg)("p",null,"See ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pactflow.io/docs/bi-directional-contract-testing/publishing#publishing-the-provider-contract--results-to-pactflow"},"Publishing the Provider Contract + Results to PactFlow")," for details and examples."),(0,o.yg)("h3",{id:"step-4-run-can-i-deploy"},"Step 4: Run can-i-deploy"),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://docs.pact.io/pact_broker/can_i_deploy/"},(0,o.yg)("inlineCode",{parentName:"a"},"can-i-deploy"))," gives you immediate feedback if you are safe to release a version of an application to a specified environment (such as ",(0,o.yg)("inlineCode",{parentName:"p"},"production"),")."),(0,o.yg)("p",null,"We recommend using the ",(0,o.yg)("inlineCode",{parentName:"p"},"pact-broker can-i-deploy")," command from ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pact.io/implementation_guides/cli/#distributions"},"CLI Tools")," for this step."),(0,o.yg)("p",null,"Our ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/pactflow/example-bi-directional-prov
1ider-postman/blob/984f635a2317faea9137d9aa52a17f77324e5568/Makefile#L74"},"examples")," use the Docker version to simplify administration."),(0,o.yg)("p",null,"The command output will provide a link to the verification results in PactFlow. Interpreting these results is contract specific."),(0,o.yg)("p",null,"Here is our pipeline to date for the first run of a provider:"),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"Provider Pipeline First Run",src:r(97971).A,title:"Provider Pipeline First Run",width:"960",height:"540"})),(0,o.yg)("h3",{id:"step-5-deploy-your-application"},"Step 5: Deploy your application"),(0,o.yg)("p",null,"If ",(0,o.yg)("inlineCode",{parentName:"p"},"can-i-deploy")," returns a successful response, you can deploy your application."),(0,o.yg)("p",null,"Once your application is deployed, you can notify PactFlow of the release - we recommend setting the branch property when you publish provider contracts and use ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pact.io/pact_broker/recording_deployments_and_releases#recording-deployments"},"record-deployment")," or ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pact.io/pact_broker/recording_deployments_and_releases#recording-releases"},"record-release")," when you deploy/release."),(0,o.yg)("p",null,"Our ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/pactflow/example-bi-directional-provider-postman/blob/984f635a2317faea9137d9aa52a17f77324e5568/Makefile#L82"},"examples")," use the Docker version to simplify administration."),(0,o.yg)("p",null,(0,o.yg)("em",{parentName:"p"},"Golden rule of deployments:")),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"The Pact Broker needs to know which versions of each application are in each environment. So, it can return the correct contracts for verification and determine whether a particular application version is safe to deploy.")),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},(0,o.yg)("inlineCode",{parentName:"p"},"record-deployment")," automatically marks the previously deployed version as undeployed and is used for APIs and consumer applications deployed to known instances.")),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},(0,o.yg)("inlineCode",{parentName:"p"},"record-release")," does NOT change the status of any previously released version and is used for mobile applications and libraries made publicly available via an application store or repository.")),(0,o.yg)("h2",{id:"integrating-it-into-your-cicd-pipeline"},"Integrating it into your CI/CD pipeline"),(0,o.yg)("p",null,"A simplified view of a CI/CD pipeline for Pact looks like this:"),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"Provider Pipeline",src:r(31706).A,title:"Provider Pipeline",width:"1886",height:"693"})),(0,o.yg)("p",null,"The standard ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pact.io/pact_nirvana"},"principles")," are still relevant. Our ",(0,o.yg)("a",{parentName:"p",href:"/docs/workshops/ci-cd"},"CI/CD workshop")," is a useful reference (NOTE: the CI/CD workshop uses the consumer-driven mode using Pact)."),(0,o.yg)("h2",{id:"other"},"Other"),(0,o.yg)("h3",{id:"other-examples-of-how-to-do-this-form-of-testing"},"Other examples of how to do this form of testing"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"https://hazelcast.com/blog/contract-first-development-using-restassured-and-openapi/"},"https://hazelcast.com/blog/contract-first-development-using-restassured-and-openapi/")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"https://www.openapi4j.org/operation-validator-adapters/spring.html"},"https://www.openapi4j.org/operation-validator-adapters/spring.html")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"https://springframework.guru/should-i-use-spring-rest-docs-or-openapi/"},"https://springframework.guru/should-i-use-spring-rest-docs-or-openapi/")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("a",{parentName:"li",href:"https://github.com/OpenAPITools/openapi-generator"},"https://github.com/OpenAPITools/openapi-generator")," (generate rest assured tests from spec)")))}u.isMDXComponent=!0},6738:(e,t,r)=>{r.d(t,{A:()=>i});
1const i=r.p+"assets/images/1-bi-directional-provider-testing-scope-0c0da83c86789b5a977edde1bd3fe2bf.png"},97971:(e,t,r)=>{r.d(t,{A:()=>i});const i=r.p+"assets/images/2-bi-directional-provider-pipeline-first-run-b1a5250e5e055636f26234582fd7f785.png"},31706:(e,t,r)=>{r.d(t,{A:()=>i});const i=r.p+"assets/images/3-bi-directional-provider-pipeline-with_consumer-e39c8b7c49dc015ad446efe6bedfba42.png"}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.