Ich habe einige einfache Unit-Test-Routinen für eine einfache Spring-Webanwendung geschrieben. Wenn ich eine @ JsonIgnore-Annotation zu einer Getter-Methode einer Ressource hinzufüge, enthält das resultierende JSON-Objekt nicht das entsprechende JSON-Element. Wenn meine Unit-Test-Routine versucht zu testen, ob dies null ist (was das erwartete Verhalten für meinen Fall ist, ich möchte nicht, dass das Kennwort im JSON-Objekt verfügbar ist), tritt bei der Testroutine eine Ausnahme auf:
java.lang.AssertionError: Kein Wert für JSON-Pfad: $ .password, Ausnahme: Keine Ergebnisse für Pfad: $ ['password']
Dies ist die Unit-Test-Methode, die ich geschrieben habe. Dabei wurde das Feld 'password' mit der Methode is (nullValue ()) getestet:
@Test
public void getUserThatExists() throws Exception {
User user = new User();
user.setId(1L);
user.setUsername("zobayer");
user.setPassword("123456");
when(userService.getUserById(1L)).thenReturn(user);
mockMvc.perform(get("/users/1"))
.andExpect(jsonPath("$.username", is(user.getUsername())))
.andExpect(jsonPath("$.password", is(nullValue())))
.andExpect(jsonPath("$.links[*].href", hasItem(endsWith("/users/1"))))
.andExpect(status().isOk())
.andDo(print());
}
Ich habe es auch mit jsonPath () versucht. Exists (), das eine ähnliche Ausnahme erhält, die besagt, dass der Pfad nicht existiert. Ich teile einige weitere Codefragmente, damit die gesamte Situation besser lesbar wird.
Die Controller-Methode, die ich teste, sieht ungefähr so aus:
@RequestMapping(value="/users/{userId}", method= RequestMethod.GET)
public ResponseEntity<UserResource> getUser(@PathVariable Long userId) {
logger.info("Request arrived for getUser() with params {}", userId);
User user = userService.getUserById(userId);
if(user != null) {
UserResource userResource = new UserResourceAsm().toResource(user);
return new ResponseEntity<>(userResource, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Ich verwende Spring Hateos Resource Assembler zum Konvertieren von Entitäten in Ressourcenobjekte. Dies ist meine Ressourcenklasse:
public class UserResource extends ResourceSupport {
private Long userId;
private String username;
private String password;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@JsonIgnore
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Ich verstehe, warum dies eine Ausnahme bekommt, auch in gewisser Weise ist der Test erfolgreich, dass es das Passwortfeld nicht finden konnte. Ich möchte diesen Test jedoch ausführen, um sicherzustellen, dass das Feld nicht vorhanden ist oder, falls vorhanden, einen Nullwert enthält. Wie kann ich das erreichen?
Es gibt einen ähnlichen Beitrag im Stapelüberlauf: Hamcrest mit MockMvc: Überprüfen Sie, ob der Schlüssel vorhanden ist, der Wert jedoch möglicherweise null ist
In meinem Fall ist das Feld möglicherweise auch nicht vorhanden.
Dies sind die Versionen der Testpakete, die ich verwende:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
Danke im Voraus.
[BEARBEITEN] Um genauer zu sein, müssen Sie beispielsweise einen Test für eine Entität schreiben, bei der Sie wissen, dass einige der Felder null oder leer sein müssen oder gar nicht existieren sollten, und Sie den Code nicht durchgehen, um zu sehen Wenn über der Eigenschaft ein JsonIgnore hinzugefügt wurde. Und Sie möchten, dass Ihre Tests bestanden werden. Wie kann ich das tun?
Bitte zögern Sie nicht, mir zu sagen, dass dies überhaupt nicht praktikabel ist, aber dennoch schön zu wissen wäre.
[EDIT] Der obige Test ist mit den folgenden älteren JSON-Pfad-Abhängigkeiten erfolgreich:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
[BEARBEITEN] Es wurde ein Quickfix gefunden, der mit der neuesten Version von jayway.jasonpath funktioniert, nachdem die Dokumentation des json path matcher von spring gelesen wurde.
.andExpect(jsonPath("$.password").doesNotExist())
quelle
.doesNotExist()
war was ich suche.Antworten:
Ich hatte das gleiche Problem mit der neueren Version. Mir scheint, dass die Funktion doesNotExist () überprüft, ob der Schlüssel nicht im Ergebnis enthalten ist:
.andExpect(jsonPath("$.password").doesNotExist())
quelle
assertThat(this.json.write(entity)).doesNotHaveJsonPathValue("@.keyl");
{}
.andExpect(jsonPath("$.*").doesNotExist())
@JsonIgnore verhält sich wie erwartet und erzeugt kein Kennwort in der json-Ausgabe. Wie können Sie also erwarten, etwas zu testen, das Sie explizit von der Ausgabe ausschließen?
Die Linie:
.andExpect(jsonPath("$.property", is("some value")));
oder sogar ein Test, dass die Eigenschaft null ist:
.andExpect(jsonPath("$.property").value(IsNull.nullValue()));
entsprechen einem json wie:
{ ... "property": "some value", ... }
wo der wichtige Teil die linke Seite ist, ist das die Existenz von "Eigentum":
Stattdessen produziert @JsonIgnore das Porperty überhaupt nicht in der Ausgabe, sodass Sie es weder im Test noch in der Produktionsausgabe erwarten können. Wenn Sie die Eigenschaft nicht in der Ausgabe haben möchten, ist dies in Ordnung, aber Sie können sie im Test nicht erwarten. Wenn Sie möchten, dass es in der Ausgabe leer ist (sowohl in prod als auch in test), möchten Sie in der Mitte eine statische Mapper-Methode erstellen, die den Wert der Eigenschaft nicht an das json-Objekt übergibt:
Mapper.mapPersonToRest(User user) {//exclude the password}
und dann wäre Ihre Methode:
@RequestMapping(value="/users/{userId}", method= RequestMethod.GET) public ResponseEntity<UserResource> getUser(@PathVariable Long userId) { logger.info("Request arrived for getUser() with params {}", userId); User user = Mapper.mapPersonToRest(userService.getUserById(userId)); if(user != null) { UserResource userResource = new UserResourceAsm().toResource(user); return new ResponseEntity<>(userResource, HttpStatus.OK); } else { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } }
Wenn Sie zu diesem Zeitpunkt erwarten, dass Mapper.mapPersonToRest einen Benutzer mit einem Nullkennwort zurückgibt, können Sie einen normalen Unit-Test für diese Methode schreiben.
PS Natürlich ist das Passwort in der DB verschlüsselt, oder? ;)
quelle
doesNotHaveJsonPath
für die Überprüfung, dass es nicht in json Körper istquelle
Ich wollte den gleichen Code wiederverwenden, den ich zum Testen des bereitgestellten Parameters verwende und der fehlt, und das habe ich mir ausgedacht
@Test void testEditionFoundInRequest() throws JsonProcessingException { testEditionWithValue("myEdition"); } @Test void testEditionNotFoundInRequest() { try { testEditionWithValue(null); throw new RuntimeException("Shouldn't pass"); } catch (AssertionError | JsonProcessingException e) { var msg = e.getMessage(); assertTrue(msg.contains("No value at JSON path")); } } void testEditionWithValue(String edition) { var HOST ="fakeHost"; var restTemplate = new RestTemplate(); var myRestClientUsingRestTemplate = new MyRestClientUsingRestTemplate(HOST, restTemplate); MockRestServiceServer mockServer; ObjectMapper objectMapper = new ObjectMapper(); String id = "userId"; var mockResponse = "{}"; var request = new MyRequest.Builder(id).edition(null).build(); mockServer = MockRestServiceServer.bindTo(restTemplate).bufferContent().build(); mockServer .expect(method(POST)) // THIS IS THE LINE I'd like to say "NOT" found .andExpect(jsonPath("$.edition").value(edition)) .andRespond(withSuccess(mockResponse, APPLICATION_JSON)); var response = myRestClientUsingRestTemplate.makeRestCall(request); } catch (AssertionError | JsonProcessingException e) { var msg = e.getMessage(); assertTrue(msg.contains("No value at JSON path")); }
quelle
Es gibt einen Unterschied zwischen der Eigenschaft, die vorhanden ist, aber einen
null
Wert hat, und der Eigenschaft, die überhaupt nicht vorhanden ist.Wenn der Test nur fehlschlagen sollte, wenn kein
null
Wert vorhanden ist, verwenden Sie:.andExpect(jsonPath("password").doesNotExist())
Wenn der Test fehlschlagen sollte, sobald die Eigenschaft vorhanden ist, auch mit einem
null
Wert, verwenden Sie:.andExpect(jsonPath("password").doesNotHaveJsonPath())
quelle