mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-05-15 00:29:38 +00:00
Merge pull request #360 from arey
* pr/360: Polish "Migrate tests to JUnit 5" Migrate tests to JUnit 5 Closes gh-360
This commit is contained in:
commit
6e4c31c681
11 changed files with 103 additions and 120 deletions
18
pom.xml
18
pom.xml
|
@ -57,6 +57,12 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Databases - Uses HSQL by default -->
|
<!-- Databases - Uses HSQL by default -->
|
||||||
|
@ -103,6 +109,18 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- end of webjars -->
|
<!-- end of webjars -->
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
|
|
@ -16,23 +16,19 @@
|
||||||
|
|
||||||
package org.springframework.samples.petclinic;
|
package org.springframework.samples.petclinic;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.samples.petclinic.vet.VetRepository;
|
import org.springframework.samples.petclinic.vet.VetRepository;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
public class PetclinicIntegrationTests {
|
class PetclinicIntegrationTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private VetRepository vets;
|
private VetRepository vets;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAll() throws Exception {
|
void testFindAll() throws Exception {
|
||||||
vets.findAll();
|
vets.findAll();
|
||||||
vets.findAll(); // served from cache
|
vets.findAll(); // served from cache
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,7 @@ import java.util.Set;
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* @author Michael Isvy Simple test to make sure that Bean Validation is working (useful
|
* @author Michael Isvy Simple test to make sure that Bean Validation is working (useful
|
||||||
* when upgrading to a new version of Hibernate Validator/ Bean Validation)
|
* when upgrading to a new version of Hibernate Validator/ Bean Validation)
|
||||||
*/
|
*/
|
||||||
public class ValidatorTests {
|
class ValidatorTests {
|
||||||
|
|
||||||
private Validator createValidator() {
|
private Validator createValidator() {
|
||||||
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
|
||||||
|
@ -42,7 +41,7 @@ public class ValidatorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotValidateWhenFirstNameEmpty() {
|
void shouldNotValidateWhenFirstNameEmpty() {
|
||||||
|
|
||||||
LocaleContextHolder.setLocale(Locale.ENGLISH);
|
LocaleContextHolder.setLocale(Locale.ENGLISH);
|
||||||
Person person = new Person();
|
Person person = new Person();
|
||||||
|
|
|
@ -23,16 +23,13 @@ import java.util.List;
|
||||||
import org.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.hamcrest.BaseMatcher;
|
import org.hamcrest.BaseMatcher;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.samples.petclinic.visit.Visit;
|
import org.springframework.samples.petclinic.visit.Visit;
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
@ -51,9 +48,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(OwnerController.class)
|
@WebMvcTest(OwnerController.class)
|
||||||
public class OwnerControllerTests {
|
class OwnerControllerTests {
|
||||||
|
|
||||||
private static final int TEST_OWNER_ID = 1;
|
private static final int TEST_OWNER_ID = 1;
|
||||||
|
|
||||||
|
@ -68,8 +64,8 @@ public class OwnerControllerTests {
|
||||||
|
|
||||||
private Owner george;
|
private Owner george;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
george = new Owner();
|
george = new Owner();
|
||||||
george.setId(TEST_OWNER_ID);
|
george.setId(TEST_OWNER_ID);
|
||||||
george.setFirstName("George");
|
george.setFirstName("George");
|
||||||
|
@ -92,7 +88,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitCreationForm() throws Exception {
|
void testInitCreationForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/new"))
|
mockMvc.perform(get("/owners/new"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(model().attributeExists("owner"))
|
||||||
|
@ -100,7 +96,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormSuccess() throws Exception {
|
void testProcessCreationFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/new")
|
mockMvc.perform(post("/owners/new")
|
||||||
.param("firstName", "Joe")
|
.param("firstName", "Joe")
|
||||||
.param("lastName", "Bloggs")
|
.param("lastName", "Bloggs")
|
||||||
|
@ -112,7 +108,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormHasErrors() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/new")
|
mockMvc.perform(post("/owners/new")
|
||||||
.param("firstName", "Joe")
|
.param("firstName", "Joe")
|
||||||
.param("lastName", "Bloggs")
|
.param("lastName", "Bloggs")
|
||||||
|
@ -126,7 +122,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitFindForm() throws Exception {
|
void testInitFindForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/find"))
|
mockMvc.perform(get("/owners/find"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(model().attributeExists("owner"))
|
||||||
|
@ -134,7 +130,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormSuccess() throws Exception {
|
void testProcessFindFormSuccess() throws Exception {
|
||||||
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
|
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
|
||||||
mockMvc.perform(get("/owners"))
|
mockMvc.perform(get("/owners"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
|
@ -142,7 +138,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormByLastName() throws Exception {
|
void testProcessFindFormByLastName() throws Exception {
|
||||||
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
||||||
mockMvc.perform(get("/owners")
|
mockMvc.perform(get("/owners")
|
||||||
.param("lastName", "Franklin")
|
.param("lastName", "Franklin")
|
||||||
|
@ -152,7 +148,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormNoOwnersFound() throws Exception {
|
void testProcessFindFormNoOwnersFound() throws Exception {
|
||||||
mockMvc.perform(get("/owners")
|
mockMvc.perform(get("/owners")
|
||||||
.param("lastName", "Unknown Surname")
|
.param("lastName", "Unknown Surname")
|
||||||
)
|
)
|
||||||
|
@ -163,7 +159,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitUpdateOwnerForm() throws Exception {
|
void testInitUpdateOwnerForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(model().attributeExists("owner"))
|
||||||
|
@ -176,7 +172,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessUpdateOwnerFormSuccess() throws Exception {
|
void testProcessUpdateOwnerFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
||||||
.param("firstName", "Joe")
|
.param("firstName", "Joe")
|
||||||
.param("lastName", "Bloggs")
|
.param("lastName", "Bloggs")
|
||||||
|
@ -189,7 +185,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessUpdateOwnerFormHasErrors() throws Exception {
|
void testProcessUpdateOwnerFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
||||||
.param("firstName", "Joe")
|
.param("firstName", "Joe")
|
||||||
.param("lastName", "Bloggs")
|
.param("lastName", "Bloggs")
|
||||||
|
@ -203,7 +199,7 @@ public class OwnerControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowOwner() throws Exception {
|
void testShowOwner() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
||||||
|
|
|
@ -24,22 +24,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.FilterType;
|
import org.springframework.context.annotation.FilterType;
|
||||||
import org.springframework.samples.petclinic.owner.Owner;
|
|
||||||
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.Pet;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetController;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetType;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetTypeFormatter;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,12 +38,11 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(value = PetController.class,
|
@WebMvcTest(value = PetController.class,
|
||||||
includeFilters = @ComponentScan.Filter(
|
includeFilters = @ComponentScan.Filter(
|
||||||
value = PetTypeFormatter.class,
|
value = PetTypeFormatter.class,
|
||||||
type = FilterType.ASSIGNABLE_TYPE))
|
type = FilterType.ASSIGNABLE_TYPE))
|
||||||
public class PetControllerTests {
|
class PetControllerTests {
|
||||||
|
|
||||||
private static final int TEST_OWNER_ID = 1;
|
private static final int TEST_OWNER_ID = 1;
|
||||||
private static final int TEST_PET_ID = 1;
|
private static final int TEST_PET_ID = 1;
|
||||||
|
@ -67,8 +57,8 @@ public class PetControllerTests {
|
||||||
@MockBean
|
@MockBean
|
||||||
private OwnerRepository owners;
|
private OwnerRepository owners;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
PetType cat = new PetType();
|
PetType cat = new PetType();
|
||||||
cat.setId(3);
|
cat.setId(3);
|
||||||
cat.setName("hamster");
|
cat.setName("hamster");
|
||||||
|
@ -79,7 +69,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitCreationForm() throws Exception {
|
void testInitCreationForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"))
|
.andExpect(view().name("pets/createOrUpdatePetForm"))
|
||||||
|
@ -87,7 +77,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormSuccess() throws Exception {
|
void testProcessCreationFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
||||||
.param("name", "Betty")
|
.param("name", "Betty")
|
||||||
.param("type", "hamster")
|
.param("type", "hamster")
|
||||||
|
@ -98,7 +88,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormHasErrors() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
||||||
.param("name", "Betty")
|
.param("name", "Betty")
|
||||||
.param("birthDate", "2015-02-12")
|
.param("birthDate", "2015-02-12")
|
||||||
|
@ -112,7 +102,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitUpdateForm() throws Exception {
|
void testInitUpdateForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attributeExists("pet"))
|
.andExpect(model().attributeExists("pet"))
|
||||||
|
@ -120,7 +110,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessUpdateFormSuccess() throws Exception {
|
void testProcessUpdateFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
||||||
.param("name", "Betty")
|
.param("name", "Betty")
|
||||||
.param("type", "hamster")
|
.param("type", "hamster")
|
||||||
|
@ -131,7 +121,7 @@ public class PetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessUpdateFormHasErrors() throws Exception {
|
void testProcessUpdateFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
||||||
.param("name", "Betty")
|
.param("name", "Betty")
|
||||||
.param("birthDate", "2015/02/12")
|
.param("birthDate", "2015/02/12")
|
||||||
|
|
|
@ -22,11 +22,12 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
@ -36,21 +37,21 @@ import static org.mockito.BDDMockito.given;
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class PetTypeFormatterTests {
|
class PetTypeFormatterTests {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PetRepository pets;
|
private PetRepository pets;
|
||||||
|
|
||||||
private PetTypeFormatter petTypeFormatter;
|
private PetTypeFormatter petTypeFormatter;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
this.petTypeFormatter = new PetTypeFormatter(pets);
|
this.petTypeFormatter = new PetTypeFormatter(pets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrint() {
|
void testPrint() {
|
||||||
PetType petType = new PetType();
|
PetType petType = new PetType();
|
||||||
petType.setName("Hamster");
|
petType.setName("Hamster");
|
||||||
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
|
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
|
||||||
|
@ -58,16 +59,18 @@ public class PetTypeFormatterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldParse() throws ParseException {
|
void shouldParse() throws ParseException {
|
||||||
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
||||||
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
||||||
assertThat(petType.getName()).isEqualTo("Bird");
|
assertThat(petType.getName()).isEqualTo("Bird");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ParseException.class)
|
@Test
|
||||||
public void shouldThrowParseException() throws ParseException {
|
void shouldThrowParseException() throws ParseException {
|
||||||
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
||||||
|
Assertions.assertThrows(ParseException.class, () -> {
|
||||||
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,17 +23,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.samples.petclinic.owner.Pet;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.VisitController;
|
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,9 +36,8 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(VisitController.class)
|
@WebMvcTest(VisitController.class)
|
||||||
public class VisitControllerTests {
|
class VisitControllerTests {
|
||||||
|
|
||||||
private static final int TEST_PET_ID = 1;
|
private static final int TEST_PET_ID = 1;
|
||||||
|
|
||||||
|
@ -56,20 +50,20 @@ public class VisitControllerTests {
|
||||||
@MockBean
|
@MockBean
|
||||||
private PetRepository pets;
|
private PetRepository pets;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void init() {
|
void init() {
|
||||||
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitNewVisitForm() throws Exception {
|
void testInitNewVisitForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID))
|
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessNewVisitFormSuccess() throws Exception {
|
void testProcessNewVisitFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
||||||
.param("name", "George")
|
.param("name", "George")
|
||||||
.param("description", "Visit Description")
|
.param("description", "Visit Description")
|
||||||
|
@ -79,7 +73,7 @@ public class VisitControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessNewVisitFormHasErrors() throws Exception {
|
void testProcessNewVisitFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
||||||
.param("name", "George")
|
.param("name", "George")
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,8 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
@ -36,7 +35,6 @@ import org.springframework.samples.petclinic.vet.VetRepository;
|
||||||
import org.springframework.samples.petclinic.visit.Visit;
|
import org.springframework.samples.petclinic.visit.Visit;
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,10 +57,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
* @author Michael Isvy
|
* @author Michael Isvy
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
|
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
|
||||||
public class ClinicServiceTests {
|
class ClinicServiceTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected OwnerRepository owners;
|
protected OwnerRepository owners;
|
||||||
|
@ -77,7 +73,7 @@ public class ClinicServiceTests {
|
||||||
protected VetRepository vets;
|
protected VetRepository vets;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindOwnersByLastName() {
|
void shouldFindOwnersByLastName() {
|
||||||
Collection<Owner> owners = this.owners.findByLastName("Davis");
|
Collection<Owner> owners = this.owners.findByLastName("Davis");
|
||||||
assertThat(owners).hasSize(2);
|
assertThat(owners).hasSize(2);
|
||||||
|
|
||||||
|
@ -86,7 +82,7 @@ public class ClinicServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindSingleOwnerWithPet() {
|
void shouldFindSingleOwnerWithPet() {
|
||||||
Owner owner = this.owners.findById(1);
|
Owner owner = this.owners.findById(1);
|
||||||
assertThat(owner.getLastName()).startsWith("Franklin");
|
assertThat(owner.getLastName()).startsWith("Franklin");
|
||||||
assertThat(owner.getPets()).hasSize(1);
|
assertThat(owner.getPets()).hasSize(1);
|
||||||
|
@ -96,7 +92,7 @@ public class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldInsertOwner() {
|
void shouldInsertOwner() {
|
||||||
Collection<Owner> owners = this.owners.findByLastName("Schultz");
|
Collection<Owner> owners = this.owners.findByLastName("Schultz");
|
||||||
int found = owners.size();
|
int found = owners.size();
|
||||||
|
|
||||||
|
@ -115,7 +111,7 @@ public class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldUpdateOwner() {
|
void shouldUpdateOwner() {
|
||||||
Owner owner = this.owners.findById(1);
|
Owner owner = this.owners.findById(1);
|
||||||
String oldLastName = owner.getLastName();
|
String oldLastName = owner.getLastName();
|
||||||
String newLastName = oldLastName + "X";
|
String newLastName = oldLastName + "X";
|
||||||
|
@ -129,7 +125,7 @@ public class ClinicServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindPetWithCorrectId() {
|
void shouldFindPetWithCorrectId() {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
assertThat(pet7.getName()).startsWith("Samantha");
|
assertThat(pet7.getName()).startsWith("Samantha");
|
||||||
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
|
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
|
||||||
|
@ -137,7 +133,7 @@ public class ClinicServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindAllPetTypes() {
|
void shouldFindAllPetTypes() {
|
||||||
Collection<PetType> petTypes = this.pets.findPetTypes();
|
Collection<PetType> petTypes = this.pets.findPetTypes();
|
||||||
|
|
||||||
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
||||||
|
@ -148,7 +144,7 @@ public class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldInsertPetIntoDatabaseAndGenerateId() {
|
void shouldInsertPetIntoDatabaseAndGenerateId() {
|
||||||
Owner owner6 = this.owners.findById(6);
|
Owner owner6 = this.owners.findById(6);
|
||||||
int found = owner6.getPets().size();
|
int found = owner6.getPets().size();
|
||||||
|
|
||||||
|
@ -171,7 +167,7 @@ public class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldUpdatePetName() throws Exception {
|
void shouldUpdatePetName() throws Exception {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
String oldName = pet7.getName();
|
String oldName = pet7.getName();
|
||||||
|
|
||||||
|
@ -184,7 +180,7 @@ public class ClinicServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindVets() {
|
void shouldFindVets() {
|
||||||
Collection<Vet> vets = this.vets.findAll();
|
Collection<Vet> vets = this.vets.findAll();
|
||||||
|
|
||||||
Vet vet = EntityUtils.getById(vets, Vet.class, 3);
|
Vet vet = EntityUtils.getById(vets, Vet.class, 3);
|
||||||
|
@ -196,7 +192,7 @@ public class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldAddNewVisitForPet() {
|
void shouldAddNewVisitForPet() {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
int found = pet7.getVisits().size();
|
int found = pet7.getVisits().size();
|
||||||
Visit visit = new Visit();
|
Visit visit = new Visit();
|
||||||
|
@ -211,7 +207,7 @@ public class ClinicServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindVisitsByPetId() throws Exception {
|
void shouldFindVisitsByPetId() throws Exception {
|
||||||
Collection<Visit> visits = this.visits.findByPetId(7);
|
Collection<Visit> visits = this.visits.findByPetId(7);
|
||||||
assertThat(visits).hasSize(2);
|
assertThat(visits).hasSize(2);
|
||||||
Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
|
Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
|
||||||
|
|
|
@ -16,13 +16,10 @@
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.system;
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
@ -36,17 +33,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
// Waiting https://github.com/spring-projects/spring-boot/issues/5574
|
// Waiting https://github.com/spring-projects/spring-boot/issues/5574
|
||||||
@Ignore
|
@Disabled
|
||||||
@WebMvcTest(controllers = CrashController.class)
|
@WebMvcTest(controllers = CrashController.class)
|
||||||
public class CrashControllerTests {
|
class CrashControllerTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTriggerException() throws Exception {
|
void testTriggerException() throws Exception {
|
||||||
mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
|
mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
|
||||||
.andExpect(model().attributeExists("exception"))
|
.andExpect(model().attributeExists("exception"))
|
||||||
.andExpect(forwardedUrl("exception")).andExpect(status().isOk());
|
.andExpect(forwardedUrl("exception")).andExpect(status().isOk());
|
||||||
|
|
|
@ -25,23 +25,20 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.ResultActions;
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for the {@link VetController}
|
* Test class for the {@link VetController}
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(VetController.class)
|
@WebMvcTest(VetController.class)
|
||||||
public class VetControllerTests {
|
class VetControllerTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
@ -49,8 +46,8 @@ public class VetControllerTests {
|
||||||
@MockBean
|
@MockBean
|
||||||
private VetRepository vets;
|
private VetRepository vets;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
Vet james = new Vet();
|
Vet james = new Vet();
|
||||||
james.setFirstName("James");
|
james.setFirstName("James");
|
||||||
james.setLastName("Carter");
|
james.setLastName("Carter");
|
||||||
|
@ -67,7 +64,7 @@ public class VetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowVetListHtml() throws Exception {
|
void testShowVetListHtml() throws Exception {
|
||||||
mockMvc.perform(get("/vets.html"))
|
mockMvc.perform(get("/vets.html"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(model().attributeExists("vets"))
|
.andExpect(model().attributeExists("vets"))
|
||||||
|
@ -75,7 +72,7 @@ public class VetControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowResourcesVetList() throws Exception {
|
void testShowResourcesVetList() throws Exception {
|
||||||
ResultActions actions = mockMvc.perform(get("/vets")
|
ResultActions actions = mockMvc.perform(get("/vets")
|
||||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
|
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
|
||||||
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
|
|
|
@ -15,20 +15,18 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.util.SerializationUtils;
|
import org.springframework.util.SerializationUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class VetTests {
|
class VetTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialization() {
|
void testSerialization() {
|
||||||
Vet vet = new Vet();
|
Vet vet = new Vet();
|
||||||
vet.setFirstName("Zaphod");
|
vet.setFirstName("Zaphod");
|
||||||
vet.setLastName("Beeblebrox");
|
vet.setLastName("Beeblebrox");
|
||||||
|
|
Loading…
Reference in a new issue