Merge branch 'eugenp:master' into master

This commit is contained in:
cesarevalenti90
2023-02-19 16:06:45 +01:00
committed by GitHub
394 changed files with 8396 additions and 2184 deletions

View File

@@ -1,2 +1,3 @@
## Relevant Articles
- [Native Images with Spring Boot and GraalVM](https://www.baeldung.com/spring-native-intro)
- [Ahead of Time Optimizations in Spring 6](https://www.baeldung.com/spring-6-ahead-of-time-optimizations)

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-3-test-pitfalls</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-3-test-pitfalls</name>
<description>Demo project for Spring Boot Testing Pitfalls</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<properties>
<org.mapstruct.version>1.5.3.Final</org.mapstruct.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
</properties>
</project>

View File

@@ -0,0 +1,13 @@
package com.baeldung.sample.pets;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PetsApplication {
public static void main(String[] args) {
SpringApplication.run(PetsApplication.class, args);
}
}

View File

@@ -0,0 +1,10 @@
package com.baeldung.sample.pets.boundary;
import lombok.Data;
@Data
public class PetDto {
private String name;
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.sample.pets.boundary;
import com.baeldung.sample.pets.domain.Pet;
import org.mapstruct.Mapper;
@Mapper(componentModel = "spring")
public interface PetDtoMapper {
PetDto map(Pet source);
Pet map(PetDto source);
}

View File

@@ -0,0 +1,28 @@
package com.baeldung.sample.pets.boundary;
import com.baeldung.sample.pets.domain.PetService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/pets")
@RequiredArgsConstructor
public class PetsController {
private final PetService service;
private final PetDtoMapper mapper;
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<PetDto> readAll() {
return service.getPets().stream()
.map(mapper::map)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.sample.pets.domain;
public record Pet(String name) {
}

View File

@@ -0,0 +1,14 @@
package com.baeldung.sample.pets.domain;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Delegate;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class PetService {
@Delegate
private final PetServiceRepository repo;
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.sample.pets.domain;
import java.util.Collection;
public interface PetServiceRepository {
boolean add(Pet pet);
void clear();
Collection<Pet> getPets();
}

View File

@@ -0,0 +1,29 @@
package com.baeldung.sample.pets.domain;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@Component
public class PetServiceRepositoryImpl implements PetServiceRepository {
private final Set<Pet> pets = new HashSet<>();
@Override
public Set<Pet> getPets() {
return Collections.unmodifiableSet(pets);
}
@Override
public boolean add(Pet pet) {
return this.pets.add(pet);
}
@Override
public void clear() {
this.pets.clear();
}
}

View File

@@ -0,0 +1,47 @@
package com.baeldung.sample.pets.boundary;
import com.baeldung.sample.pets.domain.PetService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockReset;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ExtendWith(SpringExtension.class)
public class PetDtoMapperIntegrationTest {
@Configuration
@ComponentScan(basePackageClasses = PetDtoMapper.class)
static class PetDtoMapperTestConfig {
/*
* This would be necessary because the controller is also initialized
* and needs the service, although we do not want to test it here.
*
* Solutions:
* - place the mapper into a separate sub package
* - do not test the mapper separately, test it integrated within the controller
* (recommended)
*/
@Bean
PetService createServiceMock() {
return mock(PetService.class, MockReset.withSettings(MockReset.AFTER));
}
}
@Autowired
PetDtoMapper mapper;
@Test
void shouldExist() { // simply test correct test setup
assertThat(mapper).isNotNull();
}
}

View File

@@ -0,0 +1,10 @@
package com.baeldung.sample.pets.boundary;
import org.springframework.context.annotation.ComponentScan;
/**
* Just an interface to use for compiler-checked component scanning during tests.
* @see ComponentScan#basePackageClasses()
*/
public interface PetsBoundaryLayer {
}

View File

@@ -0,0 +1,36 @@
package com.baeldung.sample.pets.boundary;
import com.baeldung.sample.pets.domain.PetService;
import com.baeldung.sample.test.slices.PetsBoundaryTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Collections;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@PetsBoundaryTest
class PetsControllerMvcIntegrationTest {
@Autowired
MockMvc mvc;
@Autowired
PetService service;
@Test
void shouldReturnEmptyArrayWhenGetPets() throws Exception {
when(service.getPets()).thenReturn(Collections.emptyList());
mvc.perform(
get("/pets")
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(content().string("[]"));
}
}

View File

@@ -0,0 +1,26 @@
package com.baeldung.sample.pets.domain;
import com.baeldung.sample.test.slices.PetsDomainTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@PetsDomainTest
class PetServiceIntegrationTest {
@Autowired
PetService service;
@Autowired // Mock
PetServiceRepository repository;
@Test
void shouldAddPetWhenNotAlreadyExisting() {
var pet = new Pet("Dog");
when(repository.add(pet)).thenReturn(true);
var result = service.add(pet);
assertThat(result).isTrue();
}
}

View File

@@ -0,0 +1,31 @@
package com.baeldung.sample.pets.domain;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class PetServiceUnitTest {
PetService service = new PetService(new PetServiceRepositoryImpl());
@Test
void shouldAddPetWhenNotAlreadyExisting() {
var pet = new Pet("Dog");
var result = service.add(pet);
assertThat(result).isTrue();
assertThat(service.getPets()).hasSize(1);
}
@Test
void shouldNotAddPetWhenAlreadyExisting() {
var pet = new Pet("Cat");
var result = service.add(pet);
assertThat(result).isTrue();
// try a second time
result = service.add(pet);
assertThat(result).isFalse();
assertThat(service.getPets()).hasSize(1);
}
}

View File

@@ -0,0 +1,10 @@
package com.baeldung.sample.pets.domain;
import org.springframework.context.annotation.ComponentScan;
/**
* Just an interface to use for compiler-checked component scanning during tests.
* @see ComponentScan#basePackageClasses()
*/
public interface PetsDomainLayer {
}

View File

@@ -0,0 +1,52 @@
package com.baeldung.sample.test.slices;
import com.baeldung.sample.pets.boundary.PetsBoundaryLayer;
import com.baeldung.sample.pets.boundary.PetsController;
import com.baeldung.sample.pets.domain.PetService;
import org.junit.jupiter.api.Tag;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockReset;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ActiveProfiles;
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.mockito.Mockito.mock;
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@WebMvcTest(controllers = PetsController.class)
@ComponentScan(basePackageClasses = PetsBoundaryLayer.class)
@Import(PetsBoundaryTest.PetBoundaryTestConfiguration.class)
// further features that can help to configure and execute tests
@ActiveProfiles({ "test", "boundary-test" })
@Tag("integration-test")
@Tag("boundary-test")
public @interface PetsBoundaryTest {
@TestConfiguration
class PetBoundaryTestConfiguration {
@Primary
@Bean
PetService createPetServiceMock() {
return mock(
PetService.class,
MockReset.withSettings(MockReset.AFTER)
);
}
}
}

View File

@@ -0,0 +1,52 @@
package com.baeldung.sample.test.slices;
import com.baeldung.sample.pets.domain.PetServiceRepository;
import com.baeldung.sample.pets.domain.PetsDomainLayer;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockReset;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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.mockito.Mockito.mock;
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtendWith(SpringExtension.class)
@ComponentScan(basePackageClasses = PetsDomainLayer.class)
@Import(PetsDomainTest.PetServiceTestConfiguration.class)
// further features that can help to configure and execute tests
@ActiveProfiles({"test", "domain-test"})
@Tag("integration-test")
@Tag("domain-test")
public @interface PetsDomainTest {
@TestConfiguration
class PetServiceTestConfiguration {
@Primary
@Bean
PetServiceRepository createPetsRepositoryMock() {
return mock(
PetServiceRepository.class,
MockReset.withSettings(MockReset.AFTER)
);
}
}
}

View File

@@ -0,0 +1,11 @@
logging:
level:
root: info
org:
springframework:
test:
context:
cache: DEBUG
spring:
main:
allow-bean-definition-overriding: true

View File

@@ -2,3 +2,4 @@
### Relevant Articles:
- [Spring Boot 3 and Spring Framework 6.0 Whats New](https://www.baeldung.com/spring-boot-3-spring-6-new)
- [Singleton Design Pattern vs Singleton Beans in Spring Boot](https://www.baeldung.com/spring-boot-singleton-vs-beans)

View File

@@ -0,0 +1,29 @@
package com.baeldung.sample.singleton;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class SingletonBeanConfig {
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public SingletonBean singletonBean() {
return new SingletonBean();
}
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public SingletonBean anotherSingletonBean() {
return new SingletonBean();
}
static class SingletonBean {
public String getValue() {
return "test";
}
}
}

View File

@@ -0,0 +1,24 @@
package com.baeldung.sample.singleton;
public final class ThreadSafeSingleInstance {
private static volatile ThreadSafeSingleInstance instance = null;
private ThreadSafeSingleInstance() {}
public static ThreadSafeSingleInstance getInstance() {
if (instance == null) {
synchronized(ThreadSafeSingleInstance.class) {
if (instance == null) {
instance = new ThreadSafeSingleInstance();
}
}
}
return instance;
}
public String getValue() {
return "test";
}
}

View File

@@ -0,0 +1,35 @@
package com.baeldung.sample.singleton;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SingletonBeanUnitTest {
@Autowired
@Qualifier("singletonBean")
private SingletonBeanConfig.SingletonBean beanOne;
@Autowired
@Qualifier("singletonBean")
private SingletonBeanConfig.SingletonBean beanTwo;
@Autowired
@Qualifier("anotherSingletonBean")
private SingletonBeanConfig.SingletonBean beanThree;
@Test
void givenTwoBeansWithSameId_whenInjectingThem_thenSameInstancesAreReturned() {
assertSame(beanOne, beanTwo);
}
@Test
void givenTwoBeansWithDifferentId_whenInjectingThem_thenDifferentInstancesAreReturned() {
assertNotSame(beanOne, beanThree);
}
}

View File

@@ -0,0 +1,16 @@
package com.baeldung.sample.singleton;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertSame;
class ThreadSafeSingleInstanceUnitTest {
@Test
void givenTwoSingletonInstances_whenGettingThem_thenSameInstancesAreReturned() {
ThreadSafeSingleInstance instanceOne = ThreadSafeSingleInstance.getInstance();
ThreadSafeSingleInstance instanceTwo = ThreadSafeSingleInstance.getInstance();
assertSame(instanceOne, instanceTwo);
}
}

View File

@@ -38,8 +38,8 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -32,8 +32,8 @@
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -2,5 +2,5 @@ package com.baeldung.boot.readonlyrepository;
import org.springframework.data.repository.CrudRepository;
public interface BookRepository extends BookReadOnlyRepository, CrudRepository<Book, Long> {
public interface BookRepository extends CrudRepository<Book, Long> {
}

View File

@@ -25,8 +25,8 @@
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>

View File

@@ -77,7 +77,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<version>2.3.1</version>
<executions>
<execution>
<id>xjc</id>
@@ -89,7 +89,7 @@
<configuration>
<packageName>com.baeldung</packageName>
<sources>
<source>src/main/resources/products.xsd</source>
<source>/${project.basedir}/src/main/resources/products.xsd</source>
</sources>
</configuration>

View File

@@ -7,3 +7,4 @@ This module contains articles about logging in Spring Boot projects with Log4j 2
- [Logging to Graylog with Spring Boot](https://www.baeldung.com/graylog-with-spring-boot)
- [Log Groups in Spring Boot 2.1](https://www.baeldung.com/spring-boot-log-groups)
- [Writing Log Data to Syslog Using Log4j2](https://www.baeldung.com/log4j-to-syslog)
- [Spring Boot Logback and Log4j2 Extensions](https://www.baeldung.com/spring-boot-logback-log4j2)

View File

@@ -9,13 +9,11 @@
<packaging>jar</packaging>
<description>Module For Spring Boot Integration with BIRT</description>
<!-- this module should use the Boot parent directly to avoid inherit -->
<!-- the logback dependency from our other parents -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>

View File

@@ -41,8 +41,8 @@
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>

View File

@@ -20,6 +20,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
@@ -59,6 +63,7 @@
<version>${swagger-codegen-maven-plugin.version}</version>
<executions>
<execution>
<id>two-responses</id>
<goals>
<goal>generate</goal>
</goals>
@@ -71,6 +76,59 @@
</configOptions>
</configuration>
</execution>
<execution>
<id>dates</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/static/event.yaml</inputSpec>
<language>spring</language>
<configOptions>
<java8>true</java8>
<dateLibrary>custom</dateLibrary>
</configOptions>
<typeMappings>
<typeMapping>DateTime=Instant</typeMapping>
<typeMapping>Date=Date</typeMapping>
</typeMappings>
<importMappings>
<importMapping>Instant=java.time.Instant</importMapping>
<importMapping>Date=java.util.Date</importMapping>
</importMappings>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>${openapi-generator.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<skipValidateSpec>true</skipValidateSpec>
<inputSpec>${project.basedir}/src/main/resources/static/event.yaml</inputSpec>
<generatorName>spring</generatorName>
<configOptions>
<java8>true</java8>
<dateLibrary>custom</dateLibrary>
<openApiNullable>false</openApiNullable>
<interfaceOnly>true</interfaceOnly>
</configOptions>
<typeMappings>
<typeMapping>DateTime=Instant</typeMapping>
<typeMapping>Date=Date</typeMapping>
</typeMappings>
<importMappings>
<importMapping>Instant=java.time.Instant</importMapping>
<importMapping>Date=java.util.Date</importMapping>
</importMappings>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
@@ -84,6 +142,7 @@
</build>
<properties>
<openapi-generator.version>6.2.1</openapi-generator.version>
<springfox.version>3.0.0</springfox.version>
<swagger-codegen-maven-plugin.version>3.0.34</swagger-codegen-maven-plugin.version>
<springdoc.version>1.6.10</springdoc.version>

View File

@@ -0,0 +1,23 @@
openapi: 3.0.0
info:
title: an example api with dates
version: 0.1.0
paths:
components:
schemas:
Event:
type: object
properties:
organizer:
type: string
startDate:
type: string
format: date
endDate:
type: string
format: date-time
ticketSales:
type: string
description: Beginning of the ticket sales
example: "01-01-2023"
pattern: "[0-9]{2}-[0-9]{2}-[0-9]{4}"

View File

@@ -0,0 +1,33 @@
package com.baeldung.dates;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.jupiter.api.Test;
import io.swagger.model.Event;
class EventUnitTest {
private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory()
.getValidator();
@Test
void givenACorrectlyFormattedTicketSales_WhenBuildingEvent_ThenSuccess() {
Set<ConstraintViolation<Event>> violations = VALIDATOR.validate(new Event().ticketSales("01-01-2024"));
assertTrue(violations.isEmpty());
}
@Test
void givenAWronglyFormattedTicketSales_WhenBuildingEvent_ThenSuccess() {
Set<ConstraintViolation<Event>> violations = VALIDATOR.validate(new Event().ticketSales("2024-01-01"));
assertEquals(1, violations.size());
}
}