Discussion: Should CDC based producer tests mock business logic or integrate with business logic [closed] - spring-cloud-contract

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
My question addresses a conceptual issue with consumer driven contracts (CDCs), not with Spring-Cloud-Contract in particular (though tagged otherwise).
A CDC usually guarantees a particular behavior of a service (producer/supplier) to its client (consumer). Many architectures (e.g. Hexagonal/Clean/Onion Architecture) have an adapter/layer to provide the technical interface(s) of the service (REST/SOAP/Messaging/...). They separate the adapter from the business logic. When tests are written based on a CDC it is possible to just test the adapter (classical unit test) and mock away the business logic.
However, the contract formally does not only specify a particular mapping of the result (from the business logic) to the data transfer object as returned by the adapter. Moreover it contains semantics wrt. to the request/response behavior: If the consumer sends a specific request with meaningful data, the producer should respond with a particular correct answer (with respect to the request).
My point for discussion/question is: Should the test on the producer side then be an integration test (integrating business logic) to check if the business logic will return the correct answer? In this case the next layer (behind business logic) might be mocked away as long as the business logic is an integral part of the test case.
In Spring CDCs (but I think in other CDC implementations as well) it is possible to distinguish between consumer and producer side and the generated test cases. For example it would be possible to reduce the producer part to check for formal correctness of the response (e.g., if a particular data item is contained and validates against a pattern) while it specifies a concrete response for the consumer part at the same time. This might lead to the (mis-) understanding on the consumer side (and backed by the consumer tests) that the concrete specified data would be returned by the producer if the consumer had sent the specified request from the CDC.
What do users of CDCs think? How do you specify behavior and to what extent do you test it on the producer side?

We describe it in the documentation - https://docs.spring.io/spring-cloud-contract/docs/2.2.5.RELEASE/reference/htmlsingle/#getting-started-introducing-spring-cloud-contract-purposes . Let me write it here for your convenience
Spring Cloud Contract’s purpose is NOT to start writing business
features in the contracts. Assume that we have a business use case of
fraud check. If a user can be a fraud for 100 different reasons, we
would assume that you would create two contracts, one for the positive
case and one for the negative case. Contract tests are used to test
contracts between applications and not to simulate full behavior.
If you check Pact's documentation (https://docs.pact.io/faq#do-i-still-need-end-to-end-tests) you'll find
Contract tests replace a certain class of system integration test (the
ones you do to make sure that you're using the API correctly and that
the API responds the way you expect). They don't replace the tests
that ensure that the core business logic of your services is working.
In case of Spring Cloud Contract - if you have a controller that delegates work to a service, then you should mock out the service and test only whether your controller can take a request and send back a proper response

Related

Microservice to Microservice Architecure using gRPC : .NET Core

So I've this Microservice architecture where there is an ApiGateway, 2 microservices i.e., Configurations. API and API-1. The Configuration. API is mainly responsible to parse the JSON request and
access the DB and update Status tables, also to fetch required data, it even adds up more values to the JSON request and send it to the API-1. API-1 is responsible to just generate report based on the json passed.
Yes I can merge the configurations. API to the API-1 and make it a single service/container but the requirement is not to merge and create two different components i.e., 1 component purely based on
fetching the data, updating the status while the other just to generate the reports.
So here are some questions:
: Should I use gRPC for the configuration.API or is there a better way to achieve this.
Thank you.
RPC is a synchronous communication so you have to come up with strong reason to use it in service to service communication. it brings the fast and performant communication on the table but also coupling to the services. if you insist use rpc it is better to use MASSTRANSIT to implement the rpc in less coupled way. however in most cases the asynchronous event-base communication is recommended to avoid coupling (in that case look at CAP theory, SAGA, circuit breaker ).
since you said
but the requirement is not to merege and create two different
components
and that is your reason and also base on the fact
also to fetch requried data, it even adds up more values to the JSON
request and send it to the API-1
i think the second one makes scenes more. how ever i cant understand why you change the database position since you said the configuration service is responsible for that.
if your report service needs request huge data to generate report you have to think about the design. there is no more profile on you domain so there cannot be an absolute answer to this. but consider data reduce from insertion or request or some sort of pre-calculation if you could and also caching responses.

Is there a software engineering concept/pattern for "service injection"?

I'm implementing a service that needs to call another service that calculates a result in a way I cannot know.
Let's say I have the following scenario:
I have some place in my code, calling a HTTP request to a defined endpoint another service returning a defined result. Now, I mustn't dictate how the result will be calculated, however I can define the result output data type I'm expecting. I want to put emphasis on this, since otherwise I would just implement the calculation logic in my service.
I would then describe it to the user:
You need to provide an HTTP service, with this exact endpoint, receiving these exact parameters, delivering this exact result type, but how you calculate the result is your job. I just need the URL of your service.
Afterwards the user of my service would configure the URL to their HTTP service into my service, so that I can make a HTTP request to {url}/defined-endpoint.
I couldn't think of another name but "service-injection" to describe this concept, since it has a resemblance to dependency injection, just that in code you don't provide an object instance, but a service that is called via http.
My question is: Is there a pattern for this concept or an alternative that more elegantly solves the general problem of outsourcing a calculation to another service?
You are defining a contract of how the interface between your service and the other service. This means that as long as the contract is respected by both parties the integration and communication will succeed. Not sure if "service-injection" is a good terminology for this. You are not injecting something in your own service, you are simply delegating the calculation to another one, but you don't inject the logic of the service into your own. And that is good because then you have a good separation of concerns and loose coupling. As long as the contract is respected, both services can be changed in whatever way it is needed and the integration would still hold.
Is there a pattern for this concept or an alternative that more elegantly solves the general problem of outsourcing a calculation to another service?
This is just how things work in a micro-services ecosystem. You have multiple services exposing APIs that communicate with each other to provide as a whole a higher-order functionality.

Do consumer contracts need to be written manually in Spring Cloud Contracts? [duplicate]

I'm just starting with Consumer-Driven Contracts for our microservice setup, and as they are mainly Spring Boot apps natural choice is Spring Cloud Contract.
But then comes the confusion. In all examples in docs contracts are defined on the producer side, and consumer retrieves them from maven repo. How it is consumer-driven if the producer defines them?
My understanding was that conceptually consumer defines them as its expectation from the producer for part of the API it uses. In addition to the previous question, is it possible with Spring Cloud Contract to define a contract on the consumer side and verify it on producers?
Thanks for this question. Yes, Spring Cloud Contract can be consumer-driven or producer driven.
The contract definitions can lay either with the producer or in an external repository. The concept of consumer-driven is not related to the fact where the contract are stored. It's related to the fact who creates them or actually who drives the change of those contracts. Another thing is whether each consumer can define a set of their own requirements. That means that one consumer can have different requirements than another one.
So in Spring Cloud Contract for the producer-driven approach, the producer just creates the contracts and it doesn't really care if different consumers use their API in a different way. The producer of the API creates e.g. 1 contract definition for all the consumers and it's the consumer's problem to align to that contract.
With consumer-driven contracts with Spring Cloud Contract, it's the consumer that suggests the changes and creates the contract definitions. The consumer sends a PR either to the producer team's repo or to a separate repo where all the contract definitions are stored. It's not the producer, but the consumer who does it. The consumer can, in the meantime, create the stubs locally without asking the producer for the permission, and prototype the API. Once the consumer has finished its work and of course talked with the producer team about the changes before, then a pull request can be sent with the suggested changes. Important thing to remember is that each consumer has their own folder with their requirements. E.g. if there are consumers example1 and example2 and there's a producer producer1 then under producer1's contract folder there will be 2 folders, one example1 and the second example2. Both will contain expectations for the particular consumer.
Then the producer takes the PR over and the verification happens on the producer side. The tests are generated. Once the implementation is written and tests are passing the stubs can be uploaded.
Finally, on the consumer side, the consumers can switch to start fetching the uploaded stubs to always get the fresh version of the stubs.
You can check a video of how full cycle of CDC is done here: https://www.youtube.com/watch?v=pDkC_00hhvA
Consumer Driven Contract tutorial: https://cloud-samples.spring.io/spring-cloud-contract-samples/tutorials/stubs_per_consumer.html
Producer Contract tutorial with contracts on the producer side: https://cloud-samples.spring.io/spring-cloud-contract-samples/tutorials/contracts_on_the_producer_side.html
Producer Contract tutorial with contracts in an external repo: https://cloud-samples.spring.io/spring-cloud-contract-samples/tutorials/contracts_external.html
All the workflows related to doing contract tests with Spring Cloud Contract can be found here - https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/using.html#using

PACT vs spring cloud contract tests [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 10 months ago.
The community reviewed whether to reopen this question 10 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I am trying to understand the better tool between PACT and Spring Cloud Contract to implement Consumer Driver Contract Tests.
I dont find any clear examples to find the pros and cons.
I want to implement CDCT, and I dont use Spring in my project. From what i understood I am assuming PACT is good to go with.
Any information or suggestions are welcomed.
Thank you.
Spring Cloud Contract allows you to define and test contracts for both REST APIs and messaging. It provides a clear and easy to use statically typed Groovy DSL and also allows for defining contracts via yaml. Both with the DSL and with yaml, defining contracts is very intuitive to anyone familiar with the standard HTTP/messaging terms, for example:
request {
method PUT()
url '/fraudcheck'
body([
"client.id": $(regex('[0-9]{10}')),
loanAmount: 99999
])
headers {
contentType('application/json')
}
}
response {
status OK()
body([
fraudCheckStatus: "FRAUD",
"rejection.reason": "Amount too high"
])
headers {
contentType applicationJson()
}
}
The producer-side tests are automatically generated by SCC and added to the project during build. If a correct implementation fulfilling the contracts is not in place, the project will not be built and deployed. If they pass, the stubs for consumer will be generated and published along with the corresponding artifact version.
On the consumer side, for HTTP, SCC provides the Stubrunner, that launches a Wiremock (in-memory http server) instance, that provides stubbed responses to matching requests. Stubrunner works with external artifact repositories such as Nexus and Artifactory and also with local m2 repositories.
SCC integrates with SpringBoot seamlessly and also integrates with Spring Cloud out of the box and can be used in place of service discovery during integration tests.
It also integrates out of the box with Pact and allows to leverage additional Pact features via hooks while using only the SCC contracts definitions.
SCC also provides a Docker-based option for implementing and testing contracts in technologies other than JVM.
DISCLAIMER: I’m a Spring Cloud Contract committer.
In contract testing, we want to make sure that the provider and consumer of an API are compatible with each other. Therefore we define our expectations as a contract using a DSL and test it against the consumer or provider of the API and if it is successful then publish it (via manually copying it or publishing to a shared repository) to the other side of the contract (Provider or consumer).
Two main providers of such functionality are: Pact and SCC (Spring Cloud Contract)
PACT: Pact is a consumer-driven contract meaning that we define and validate the contract on the consumer side and then push it to the provider side for validation.
Additionally, Pact is not limited to a specific framework or even language (pact-JVM is there for a Java application). Also, it integrates well with Spring (Boot) and you can define pact test while starting the whole application (#SpringBootTest) or during Slice testing (#WebMvcTest).
SCC: Generally it encourages provider-driven contracts, meaning that you define the contract on the provider side and if it validates then publish it to the consumer side. However, we can do it the other way around or even we can define the contract separately and test it manually against the producer and consumer.

Who is the consumer in a POST scenario?

I have read that on Pact, the consumer is the one initiating the request. I have a service (let's call it A) that is used to draw pictures that will then be submitted (via POST) to a service (let's call it B) that will process those inputs and generate albums.
My question is: If the service B is the expert on knowing which kind of inputs and in which format should receive in order to create albums, how come is service A the consumer and therefore the one that will be writing the contract? Shouldn't it be the service B that specifies what kind of data should be receiving?
From [1]:
A component that initiates a HTTP request to another component (the service Provider). Note that this does not depend on the way the data flows - whether it is a GET or a PUT / POST / PATCH, the Consumer is the initiator of the HTTP request.
But I think your question is really asking about consumer driven contract testing [2]. You're conflating who is building the service with expertise / understanding of the requirements for its existence. The Consumer knows what it needs from the service, and the Provider knows how to implement it.
Consumer driven contracts reverses the typical API design process of creating an API first and then consumers coming along to use it. First, the consumer specifies what it requires, publishes the expectations as a contract and the Provider then implements it.
Pact generally assumes this mode, but it's not strictly necessary (i.e. the Provider API can exist in advance).
[1] https://docs.pact.io/documentation/how_does_pact_work.html
[2] https://martinfowler.com/articles/consumerDrivenContracts.html

Resources