Ich war verwirrt über die Validierung (die durch Annotation definiert werden kann), die die Javax-Seite hat, und die Validierungstestmethode auf der Federseite, daher werde ich sie wie folgt zusammenfassen. Übrigens denken Sie vielleicht, dass Sie alles mit benutzerdefinierten Anmerkungen auf der Javax-Seite machen sollten, aber ich konnte es nicht wie erwartet testen, also musste ich es auf der Spring-Seite machen.
So wechseln Sie zu einem Feld in Ihrer eigenen Validierung, wenn Sie einen Test ausführen
Überprüfen Sie zunächst die Zielklasse.
PasswordForm.java
package com.ssp_engine.user.domain.model;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import com.ssp_engine.user.domain.model.validation.ConfirmPassword;
import com.ssp_engine.user.domain.model.validation.ValidGroup1;
import com.ssp_engine.user.domain.model.validation.ValidGroup2;
import com.ssp_engine.user.domain.model.validation.ValidGroup3;
import com.ssp_engine.user.domain.model.validation.ValidGroup4;
import lombok.Data;
@Data
@ConfirmPassword(field = "password", groups = ValidGroup4.class)
public class PasswordForm {
@NotBlank(groups = ValidGroup1.class)
private String currentPassword;
@NotBlank(groups = ValidGroup1.class)
@Length(min = 4, max = 8, groups = ValidGroup2.class)
@Pattern(regexp="^[a-zA-Z0-9]+$", groups = ValidGroup3.class)
private String password;
@NotBlank(groups = ValidGroup1.class)
private String confirmPassword;
}
Dies ist eine Formularklasse zum Bearbeiten Ihres eigenen Kennworts auf dem Verwaltungsbildschirm eines allgemeinen Webdienstes wie diesem.
currentPassword
ist das aktuell angemeldete Passwort
password
ist das zu ändernde Passwort
verifyPassword
ist das Bestätigungspasswort
Jeder hat also eine Validierung der regulären Ausdrücke "@ NotBlank" und "@ Pattern".
In currentPassword
gibt es eine Validierung, um sie mit dem aktuell angemeldeten Passwort zu vergleichen.
LoginPassAndFormPassValidator.java
package com.ssp_engine.user.domain.model.validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.ssp_engine.user.domain.model.PasswordForm;
@Component
public class LoginPassAndFormPassValidator implements Validator {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public boolean supports(Class<?> clazz) {
return PasswordForm.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
PasswordForm form = (PasswordForm) target;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
UserDetails principal = (UserDetails) auth.getPrincipal();
String userPass = principal.getPassword();
if (form.getCurrentPassword() == null) {
return;
}
if (!this.passwordEncoder.matches(form.getCurrentPassword(), userPass)) {
errors.rejectValue("currentPassword",
"LoginPassAndFormPassValidator.PasswordForm.currentPassword",
"Es unterscheidet sich von dem Passwort, mit dem Sie angemeldet sind.");
}
}
}
Auf der Controllerseite benutze ich es nach @ InitBinder
.
Wir werden diese Frühjahrs- und Javax-Validatoren testen.
Und für den Test ist es einfacher, den Testinhalt zu trennen, da der Test auf der Controllerseite und der Test der Formularklasse nicht mehr getrennt werden müssen. Es sieht also so aus.
PasswordFormTests.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class PasswordFormTests {
private PasswordForm passwordForm = new PasswordForm();
private BindingResult bindingResult = new BindException(passwordForm, "PasswordForm"); //①
@Autowired
@Qualifier("loginPassAndFormPassValidator") //②
/*Federseite*/
private org.springframework.validation.Validator loginPassAndFormPassValidator;
/*Javax Seite*/
private static Validator validator; //③
@BeforeClass
öffentlicher statischer Void-Initialisierungsprozess() { //④
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.getValidator();
}
@Before
public void Wert festlegen() throws Exception{ //⑤
this.passwordForm.setCurrentPassword("currentpassword");
this.passwordForm.setConfirmPassword("password");
this.passwordForm.setPassword("password");
}
}
① ・ ・ ・ Feld zum Empfangen des Ergebnisses nach Ausführung des Validators
② ・ ・ ・ Da es notwendig war, explizit anzugeben, welche Klasse, wurde sie mit @ Qualifier
angegeben.
Wanted ・ ④ ・ ・ ・ Ich wollte eine Bean erhalten, indem ich sie mit @ AutoWired
spezifizierte, aber es hat nicht funktioniert, deshalb erstelle ich explizit eine Bean.
⑤ ・ ・ ・ Für das Zielobjekt wird ein Wert festgelegt.
Wenn ich fertig bin, mache ich einen Gorigori-Test und es sieht so aus. Überprüfen Sie zunächst, ob keine Fehler vorliegen.
PasswordFormTests.java
@Test
@WithMockUser(username = "username",
password ="$2a$10$p3/Malw3/KWyfOlPwWoUCulx4iDb2C/nmo6x8P2svXjfJQ5ETLhG2",
roles = "USER")
public void kein Fehler() throws Exception{
loginPassAndFormPassValidator.validate(this.passwordForm, bindingResult); //①
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class,ValidGroup2.class,ValidGroup3.class,ValidGroup4.class); //②
assertThat(bindingResult.getFieldError(), is(nullValue())); //③
assertThat(violations.size(), is(0)); //④
}
・ ・ ・ ・ Die Validierung auf der Federseite wird ausgeführt. Das Zielobjekt wird im ersten Argument angegeben, und das Objekt bindingResult
, das das Ergebnis speichert, wird im zweiten Argument angegeben.
Con ・ ・ ・ ConstraintViolation
gibt eine Reihe von Objekten zurück, in denen der Inhalt der Constraint-Verletzung gespeichert ist, und das Zielobjekt ist das erste Argument für validate. Da ValidGroup im zweiten Argument angegeben wurde, wird angegeben, welche Validierung aktiviert ist.
② ・ ・ ・ Empfängt das Ergebnis auf der Federseite mit bindingResult
und prüft, ob es Null ist.
③ ・ ・ ・ Das Ergebnis auf der Javax-Seite wird mit rows.size ()
bemessen und überprüft, ob es 0 ist.
@ WithMockUser
befindet sich im angemeldeten Zustand, da die Anmeldeinformationen mit loginPassAndFormPassValidator
abgerufen werden mussten.
Als ich herausfand, dass dies kein Fehler war, schrieb ich es so.
PasswordFormTests.java
@Test
@WithMockUser(username = "username",
password ="currentpassword",
roles = "USER")
public void Anmeldepfad und Eingabepfad sind unterschiedlich() throws Exception{
loginPassAndFormPassValidator.validate(this.passwordForm, bindingResult);
assertThat(bindingResult.getFieldError("currentPassword"), is(bindingResult.getFieldError()));
assertThat(bindingResult.getFieldError().getDefaultMessage(), is("Es unterscheidet sich von dem Passwort, mit dem Sie angemeldet sind."));
}
@Test
public void Das aktuelle Passwort ist leer() throws Exception{
this.passwordForm.setCurrentPassword("");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "currentPassword"), is(instanceOf(NotBlank.class))); //①
}
private Annotation getAnnotation(Set<ConstraintViolation<PasswordForm>> violations, String path) { //②
return violations.stream()
.filter(cv -> cv.getPropertyPath().toString().equals(path))
.findFirst()
.map(cv -> cv.getConstraintDescriptor().getAnnotation())
.get();
}
① ・ ・ ・ Überprüfen Sie, welche Anmerkung den Fehler verursacht. (2) ... Ich erstelle eine Methode, um eine Instanz der Annotation abzurufen, die mit einem Fehler abgespielt wurde.
Das ganze Bild sieht so aus.
PasswordFormTests.java
package com.ssp_engine.user.domain.model;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import com.ssp_engine.user.domain.model.validation.ConfirmPassword;
import com.ssp_engine.user.domain.model.validation.ValidGroup1;
import com.ssp_engine.user.domain.model.validation.ValidGroup2;
import com.ssp_engine.user.domain.model.validation.ValidGroup3;
import com.ssp_engine.user.domain.model.validation.ValidGroup4;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PasswordFormTests {
private PasswordForm passwordForm = new PasswordForm();
private BindingResult bindingResult = new BindException(passwordForm, "PasswordForm");
@Autowired
@Qualifier("loginPassAndFormPassValidator")
/*Federseite*/
private org.springframework.validation.Validator loginPassAndFormPassValidator;
/*Javax Seite*/
private static Validator validator;
@BeforeClass
öffentlicher statischer Void-Initialisierungsprozess() {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.getValidator();
}
@Before
public void Wert festlegen() throws Exception{
this.passwordForm.setCurrentPassword("currentpassword");
this.passwordForm.setConfirmPassword("password");
this.passwordForm.setPassword("password");
}
@Test
@WithMockUser(username = "username",
password ="$2a$10$p3/Malw3/KWyfOlPwWoUCulx4iDb2C/nmo6x8P2svXjfJQ5ETLhG2",
roles = "USER")
public void kein Fehler() throws Exception{
loginPassAndFormPassValidator.validate(this.passwordForm, bindingResult);
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class,ValidGroup2.class,ValidGroup3.class,ValidGroup4.class);
assertThat(bindingResult.getFieldError(), is(nullValue()));
assertThat(violations.size(), is(0));
}
@Test
@WithMockUser(username = "username",
password ="currentpassword",
roles = "USER")
public void Anmeldepfad und Eingabepfad sind unterschiedlich() throws Exception{
loginPassAndFormPassValidator.validate(this.passwordForm, bindingResult);
assertThat(bindingResult.getFieldError("currentPassword"), is(bindingResult.getFieldError()));
assertThat(bindingResult.getFieldError().getDefaultMessage(), is("Es unterscheidet sich von dem Passwort, mit dem Sie angemeldet sind."));
}
@Test
public void Das aktuelle Passwort ist leer() throws Exception{
this.passwordForm.setCurrentPassword("");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "currentPassword"), is(instanceOf(NotBlank.class)));
}
@Test
public void Passwort ist leer() throws Exception{
this.passwordForm.setPassword("");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "password"), is(instanceOf(NotBlank.class)));
}
@Test
public void Bestätigungspasswort ist leer() throws Exception{
this.passwordForm.setConfirmPassword("");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup1.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "confirmPassword"), is(instanceOf(NotBlank.class)));
}
@Test
public void Wenn das Bestätigungskennwort und das Eingabekennwort unterschiedlich sind() throws Exception{
this.passwordForm.setPassword("aiueo");
this.passwordForm.setConfirmPassword("kakikukeko");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup4.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "password"), is(instanceOf(ConfirmPassword.class)));
}
@Test
public void Wenn das Passwort aus 8 Zeichen oder mehr besteht() throws Exception{
this.passwordForm.setPassword("aiueokakikukeko");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup2.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "password"), is(instanceOf(Length.class)));
}
@Test
public void Wenn das Passwort maximal 4 Zeichen lang ist() throws Exception{
this.passwordForm.setPassword("aiu");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup2.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "password"), is(instanceOf(Length.class)));
}
@Test
public void Wenn das Kennwort keine alphanumerischen Zeichen mit halber Breite enthält() throws Exception{
this.passwordForm.setPassword("Es ist ein Test");
Set<ConstraintViolation<PasswordForm>> violations =
validator.validate(this.passwordForm,ValidGroup3.class);
assertThat(violations.size(), is(1));
assertThat(getAnnotation(violations, "password"), is(instanceOf(Pattern.class)));
}
private Annotation getAnnotation(Set<ConstraintViolation<PasswordForm>> violations, String path) {
return violations.stream()
.filter(cv -> cv.getPropertyPath().toString().equals(path))
.findFirst()
.map(cv -> cv.getConstraintDescriptor().getAnnotation())
.get();
}
}
Ich wäre dankbar, wenn jemand es hilfreich finden könnte.
Recommended Posts