Во время теста containsExactlyInAnyOrder получаю NullPointerException
Это учебный проект, в контроллере метод, который возвращает список студентов найденных по возрасту. Пишу тест для этого метода getStudentsByAge() и при сравнивании коллекций получаю NullPointerException.
Класс Student
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
@ManyToOne
@JoinColumn(name = "faculty_id")
@JsonBackReference
private Faculty faculty;
public Student(Long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(Long id, String name, int age, Faculty faculty) {
this.id = id;
this.name = name;
this.age = age;
this.faculty = faculty;
}
public Student(){}
//get and set
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return getAge() == student.getAge() && getId().equals(student.getId()) && getName().equals(student.getName());
}
Класс StudentController
@RestController
@RequestMapping("student")
public class StudentController {
private final StudentServiceImpl studentService;
public StudentController(StudentServiceImpl studentService) {
this.studentService = studentService;
}
@GetMapping("{id}")
public ResponseEntity<Student> getStudentInfo(@PathVariable Long id){
Student student = studentService.findStudent(id);
if (student == null){
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(student);
}
@PostMapping("/add")
public ResponseEntity<Student> createStudent(@RequestBody Student student){
Student addStudent = studentService.addStudent(student);
return ResponseEntity.created(URI.create("")).body(addStudent);
}
@GetMapping(value = "/age", params = {"age"})
public Collection<Student> getStudentsByAge(@RequestParam(value = "age") Integer age){
return studentService.getStudentsByAge(age);
}
@GetMapping("/get")
public Collection<Student> getAll(){
return studentService.getAllStudents();
}
@GetMapping("/ages")
public ResponseEntity<Collection<Student>> getStudentsByAgeBetween(@RequestParam Integer min, @RequestParam Integer max){
return ResponseEntity.ok(studentService.getStudentsByAgeBetween(min, max));
}
}
Класс SchoolApplicationTests
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SchoolApplicationTests {
private String name = "Tom";
private String name1 = "Piter";
private String name2 = "Tod";
private String name3 = "Monika";
private String name4 = "Bob";
private int age = 27;
private int age18 = 18;
private int age22 = 22;
private int age28 = 28;
private int age30 = 30;
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Profile("dev")
@Bean(initMethod = "start", destroyMethod = "stop")
public Server h2Server() throws SQLException {
return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092");
}
@Test
public void createStudentTest(){
Student student = givenStudentWith(name, age);
ResponseEntity<Student> response = whenSendingCreateStudentRequest(student);
thenStudentHasBeenCreated(response);
}
@Test
public void getStudentInfoTest(){
Student student = givenStudentWith(name, age);
ResponseEntity<Student> createResponse = whenSendingCreateStudentRequest(student);
thenStudentHasBeenCreated(createResponse);
Student createStudent = createResponse.getBody();
assert createStudent != null;
thenStudentWithIdHasBeenFound(createStudent.getId(), createStudent);
}
@Test
public void getStudentsByAge(){
Student student18 = givenStudentWith(name1, age18);
Student student22 = givenStudentWith(name2, age22);
Student student28 = givenStudentWith(name3, age28);
Student student30 = givenStudentWith(name4, age30);
whenSendingCreateStudentRequest(student18);
whenSendingCreateStudentRequest(student22);
whenSendingCreateStudentRequest(student28);
whenSendingCreateStudentRequest(student30);
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("age", "28");
thenStudentsFoundByCriteria(queryParams, student28);
}
private ResponseEntity<Student> whenSendingCreateStudentRequest(Student student){
URI uri = URI.create(getUriBuilder().cloneBuilder().path("/add").toUriString());
return restTemplate.postForEntity(uri, student, Student.class);
}
private void thenStudentHasBeenCreated(ResponseEntity<Student> response){
Assertions.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
Assertions.assertThat(response.getBody()).isNotNull();
Assertions.assertThat(response.getBody().getId()).isNotNull();
}
private void thenStudentWithIdHasBeenFound(Long studentId, Student student){
URI uri = getUriBuilder().cloneBuilder().path("/{id}").buildAndExpand(studentId).toUri();
ResponseEntity<Student> response = restTemplate.getForEntity(uri, Student.class);
Assertions.assertThat(response.getBody()).isEqualTo(student);
Assertions.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
private void thenStudentsFoundByCriteria(MultiValueMap<String, String> queryParams, Student... students){
URI uri = getUriBuilder().cloneBuilder().path("/age").queryParams(queryParams).build().toUri();
System.out.println("uri.toString() = " + uri);
System.out.println("students = " + Arrays.toString(students));
ResponseEntity<Collection<Student>> response = restTemplate.exchange(
uri,
HttpMethod.GET,
null,
new ParameterizedTypeReference<Collection<Student>>() {
});
System.out.println("response = " + response);
Assertions.assertThat(response.getBody()).isNotNull();
Assertions.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
Collection<Student> actualResult = response.getBody();
System.out.println("actualResult = " + actualResult);
resetIds(actualResult);
System.out.println("actualResult = " + actualResult);
Assertions.assertThat(actualResult).containsExactlyInAnyOrder(students);
}
private Student givenStudentWith(String name, int age){
return new Student(name, age);
}
private void resetIds(Collection<Student> students){
students.forEach(item -> item.setId(null));
}
private UriComponentsBuilder getUriBuilder(){
return UriComponentsBuilder.newInstance()
.scheme("http")
.host("localhost")
.port(port)
.path("/student");
}
}
Запускаю тест и он падает с ошибкой:
uri.toString() = http://localhost:52713/student/age?age=28
students = [Student[id=null, name='Monika', age=28]]
response = <200,[Student[id=3, name='Monika', age=28]],[Content-Type:"application/json", Transfer-Encoding:"chunked", Date:"Wed, 30 Mar 2022 13:09:39 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
actualResult = [Student[id=3, name='Monika', age=28]]
actualResult = [Student[id=null, name='Monika', age=28]]
java.lang.NullPointerException
at ru.hogwarts.school.model.Student.equals(Student.java:79)
at org.assertj.core.internal.StandardComparisonStrategy.areEqual(StandardComparisonStrategy.java:113)
at org.assertj.core.internal.StandardComparisonStrategy.lambda$iterableContains$1(StandardComparisonStrategy.java:131)
at java.base/java.util.stream.MatchOps$1MatchSink.accept(MatchOps.java:90)
at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1632)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:528)
at org.assertj.core.internal.StandardComparisonStrategy.iterableContains(StandardComparisonStrategy.java:131)
at org.assertj.core.internal.Iterables.iterableContains(Iterables.java:358)
at org.assertj.core.internal.Iterables.assertContainsExactlyInAnyOrder(Iterables.java:1360)
at org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrderForProxy(AbstractIterableAssert.java:440)
at org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrder(AbstractIterableAssert.java:433)
at ru.hogwarts.school.SchoolApplicationTests.thenStudentsFoundByCriteria(SchoolApplicationTests.java:137)
at ru.hogwarts.school.SchoolApplicationTests.getStudentsByAge(SchoolApplicationTests.java:90)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
2022-03-30 16:09:40.511 INFO 17488 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-03-30 16:09:40.512 INFO 17488 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
2022-03-30 16:09:40.524 INFO 17488 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown initiated...
2022-03-30 16:09:40.528 INFO 17488 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown completed.
Process finished with exit code -1
Ошибка NullPointerException возникает в методе equals класса Student. В students и actualResult лежат одинаковые студенты. Помогите решить этот ребус