04tudor / loyalty-campaign-service

Java project Loyalty Campaign Service using Hexagonal Architecture
0 stars 0 forks source link

Add Integration testing #32

Closed DemiusAcademius closed 5 months ago

DemiusAcademius commented 5 months ago

package md.maib.commons.integration.test;

import org.junit.jupiter.api.Tag; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource;

import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;

import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Tag("integration") @SpringBootTest(webEnvironment = RANDOM_PORT, args = "build.image=false") @TestPropertySource("classpath:integration-tests.properties") public @interface IntegrationTest { }

DemiusAcademius commented 5 months ago

package md.maib.retail.loyalty.campagin.rest;

import au.com.dius.pact.provider.junit5.HttpTestTarget; import au.com.dius.pact.provider.junit5.PactVerificationContext; import au.com.dius.pact.provider.junitsupport.IgnoreNoPactsToVerify; import au.com.dius.pact.provider.junitsupport.Provider; import au.com.dius.pact.provider.junitsupport.VerificationReports; import au.com.dius.pact.provider.junitsupport.loader.PactFolder; import au.com.dius.pact.provider.spring.junit5.PactVerificationSpringProvider; import md.maib.commons.integration.test.IntegrationTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.TestPropertySource;

import javax.annotation.Nullable; import java.util.List;

@IntegrationTest @TestPropertySource("classpath:/integration-tests.properties") @Provider("loyalty-campaign-service") @PactFolder("pacts") @IgnoreNoPactsToVerify @VerificationReports(value = {"console", "json"}, reportDir = "target/pact/reports") class ApplicationVerificationTest {

@BeforeEach
void before(@Nullable PactVerificationContext context, @LocalServerPort int port,
            @Autowired(required = false) List<StateHandler> stateHandlers) {

    if (context != null && stateHandlers != null) {
        context.withStateChangeHandlers(stateHandlers.toArray())
                .setTarget(new HttpTestTarget("localhost", port, "/"));
    }
}

@TestTemplate
@ExtendWith(PactVerificationSpringProvider.class)
void verification(@Nullable PactVerificationContext context) {
    if (context != null) {
        context.verifyInteraction();
    }
}

}

DemiusAcademius commented 5 months ago

integration-test.properties

embedded.service.enabled=false

DemiusAcademius commented 5 months ago

{ "consumer": { "name": "loyalty-campaign-gateway" }, "interactions": [ { "description": "a request with params for applications", "providerStates": [ { "name": "get campaign by id" } ], "request": { "method": "GET", "path": "/api/campaigns/fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91" }, "response": { "body": { "id": "fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91", "name": "Some other campaign", "interval": { "start": "2018-11-30T18:35:24Z", "end": "2023-12-31T18:35:24Z" }, "tags": [ "PARTNER", "PROMO" ], "rules": [ { "id": "587936e3-80da-4ff3-abfe-e5eea796135e", "conditions": [ { "negated": false, "field": "MERCHANT_ID", "operator": "EQ", "value": "Linella" } ], "sponsor": "PARTNER", "rate": 5.00 } ], "isDefault": false, "createdAt": "2018-11-30T18:35:24Z" }, "headers": { "Content-Type": "application/json" }, "status": 200 } }, { "description": "a request with params for applications", "providerStates": [ { "name": "find campaign by name" } ], "request": { "method": "GET", "path": "/api/campaigns", "query": { "name": [ "Some campa" ], "tags": [ "PARTNER, PROMO" ] } }, "response": { "body": [ { "value": "fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91" } ], "headers": { "Content-Type": "application/json" }, "status": 200 } }, { "description": "a request with params for applications", "providerStates": [ { "name": "complete campaign" } ], "request": { "method": "POST", "headers": { "Content-Type": "application/json" }, "path": "/api/campaigns/fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91/completion", "body": { "completedAt": "2025-12-31" } }, "response": { "status": 204 } }, { "description": "a request with params for applications", "providerStates": [ { "name": "register campaign" } ], "request": { "method": "POST", "headers": { "Content-Type": "application/json" }, "path": "/api/campaigns", "body": { "name": "Some campaign", "startInclusive": "2018-01-01", "endExclusive": "2025-12-31", "tags": [ "PROMO" ], "rules": [ { "conditions": [ { "negated": false, "fieldName": "MCC", "operator": "IN", "operatorModifier": null, "value": "123,456" } ], "effect": { "sponsor": "BANK", "rate": 5.0 } } ] } }, "response": { "headers": { "Location": "http://localhost:55555/api/campaigns/fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91" }, "status": 201, "matchingRules": { "header": { "Location": { "combine": "AND", "matchers": [ { "match": "regex", "regex": "http://localhost:\\d+/api/campaigns/fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91" } ] } } } } } ], "metadata": { "pact-jvm": { "version": "4.6.1" }, "pactSpecification": { "version": "3.0.0" } }, "provider": { "name": "loyalty-campaign-service" } }

DemiusAcademius commented 5 months ago

@State("get campaign by id") void getCampaignById() { var id = fromString("fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91"); var interval = Interval.of(parse("2018-11-30T18:35:24.00Z"), parse("2023-12-31T18:35:24.00Z")); var campaign = new CampaignEntity( new CampaignId(id), new CampaignName("Some other campaign"), interval, List.of( new RuleEntity( new RuleId(fromString("587936e3-80da-4ff3-abfe-e5eea796135e")), List.of( new ConditionEntity( new ConditionId(fromString("de1bef3f-acae-48da-8584-410683553cef")), false, PurchaseField.MERCHANT_ID, ConditionOperator.EQ, null, "Linella") ), new CashbackEffectEntity(new EffectId(fromString("65f14e63-9ad9-4d9e-abdc-c9b153ceb8cb")), CampaignSponsor.PARTNER, new BigDecimal("5.00")) ) ), parse("2018-11-30T18:35:24.00Z") ); when(getCampaignByIdUseCase.getCampaign(any())).thenReturn(Optional.of(campaign)); when(campaignIsDefaultUseCase.isDefault(any())).thenReturn(false); when(listCampaignTagsUseCase.listCampaignTags(any())).thenReturn(List.of(CampaignTag.PARTNER, CampaignTag.PROMO)); }

DemiusAcademius commented 5 months ago

mvn test -Dgroups=integration

DemiusAcademius commented 5 months ago

simple state for RegisterCampaign

@State("register campaign")
void registerCampaign() {
      var id = fromString("fe5cea5a-71ce-44cd-9b7a-1aba11dc5a91");
      when(registrationCampaignUseCase.registerCampaign(any())).thenReturn(Either.right(new CampaignId(id)));
}
04tudor commented 5 months ago

the same error

JSON parse error: Cannot invoke "String.length()" because "name" is null]

,can it be because of Controller method?

@PostMapping @Transactional public ResponseEntity registerCampaign(@RequestBody RegisterCampaignRequest request) { var validated = RegisterCampaign.create( request.metaInfo(), request.startInclusive(), request.endExclusive(), request.state(), request.loyaltyEventType(), request.rules() );

    return validated.fold(
            violations -> {
                throw responseExceptionFromViolations(violations);
            },
            command -> {
                var result = registrationCampaignUseCase.registerCampaign(command);
                return result.map(campaignId -> {
                    var location = ServletUriComponentsBuilder
                            .fromCurrentRequest()
                            .path("/{id}")
                            .buildAndExpand(campaignId.campaignId().toString()).toUri();
                    return ResponseEntity.created(location).build();
                }).getOrElse(() -> ResponseEntity.notFound().build());
            }
    );
}