0

Given the following classes :

class Contact{
   @Getter
   @Setter
   @Email
   private String mail;
}
@RestController
class ContactController{
   @PostMapping(path = "/contacts")
    public ResponseEntity<Contact> addContact(
            @Valid @RequestBody Contact contact) {
     ....
    }
}

How can I test in a gherkin scenario ?

I've tried the following :

  Scenario Outline: validation failed use-case
    Given I am authenticated as "<userFirstName>"
    When I register a new contact "<contactJsonLocation>"
    Then it should throw an ConstraintViolationException of contact
    Examples:
      | userFirstName | contactJsonLocation                  | 
      | Simon         | contactWithMailNotWellFormatted.json |

Steps code :

public CreateContactSteps(ContactController contactController) {
  When("^I register a new contact \"([^\"]*)\"$",
    (String contactJsonLocation) -> {
      try {
        Contact contact;
        String jsonContact = Files.readString(Paths.get(new ClassPathResource("files/" + contactJsonLocation).getURI()));   
        contact = objectMapper.readValue(jsonContact, Contact.class);
        String id = UUID.randomUUID().toString();
        contact.setId(id);
        createContactAttempt.setId(id);
        createContactAttempt.setMail(contact.getMail());
        contactController.addContact(contact);
      } catch (IOException e) {
        throw new RuntimeException(e);
      } catch (ConstraintViolationException e) {                                
        createContactAttempt.lastException = e;
       }
  });
  
  Then("^it should throw an ConstraintViolationException of contact$",
    () -> {
       Assertions.assertTrue(createContactAttempt.lastException instanceof ConstraintViolationException);
        createContactAttempt.lastException = null;
    });

When I'm testing to create a new contact after starting my spring boot app all is going well on the validation part, meaning I'm receiving the expected 400 error. But when I'm calling the ContactController from my test context, it fails to valid and the contact is created. I'm guessing it has something to do with spring doing some magic behind the scene, but what ? Right now I'm initiating myself the cucumber application context like this (and I might be doing something wrong, I'm open to suggestion / good criticism) :

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty", "html:FeaturesReport.html"},
        features = {"src/test/resources/features"})
public class AllAcceptanceTest {
}

@CucumberContextConfiguration
@ContextConfiguration(classes = {BeanConfiguration.class})
public class ContextConfigurationTesting implements En {
}

@Configuration
@RequiredArgsConstructor
public class ControllerConfiguration {
    @Bean
    public ContactController contactController() {
        return new ContactController(
                ... //every other bean the controller need 
        );
    }
    ...
}

RVA
  • 790
  • 3
  • 14
  • 33

1 Answers1

1

The @Valid annotation signals the caller of addContact that the object should be valid. By directly calling addContact you are bypassing that. You may want to consider using MockMvc to call your controller instead.

I would suggest using Spring boot to setup your application context instead. Spring Boot has a rich set of features that let you test many aspects of your application easily.

M.P. Korstanje
  • 10,426
  • 3
  • 36
  • 58
  • How can I let spring boot set up the majority of my beans but not for some. I'm using some "InMemoryRepository" in my context test to avoid the set up of a database. I need to tell spring to initialize those bean with the in memory implementation instead of the production one (mongodb actually) – RVA Dec 17 '22 at 08:21
  • Spring can do that. Read the document I linked. Look for `JDBC` or `JPA`. Though it would be a bad idea to keep trying to achieve your current objective without fully familiarizing yourself with Spring Boot and the tests it provides first. – M.P. Korstanje Dec 17 '22 at 09:51