Controller-Tests sind etwas Besonderes, daher mache ich mir Sorgen. .. Notieren Sie sich, wie Sie einen Test für den geschäftlichen Spring Boot Controller schreiben.
Ich werde einen Test für den folgenden Controller schreiben.
@Controller
@RequestMapping("/")
public class DemoController {
/**
* index
*/
@RequestMapping(path = "home", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav) {
//Legen Sie einen Wert für die Nachricht fest
mav.addObject("message", "hello world");
mav.setViewName("index");
return mav;
}
/**
*Bildschirmanzeige eingeben
*/
@RequestMapping(path = "form", method = RequestMethod.GET)
public ModelAndView form(ModelAndView mav, Form form) {
//Legen Sie den Anfangswert für den Namen des Formulars fest
form.setName("hoge");
mav.addObject("form", form);
mav.setViewName("demoForm");
return mav;
}
/**
*Erhalten Sie das Ergebnis und die Validierung
*/
@RequestMapping(path = "form", method = RequestMethod.POST)
public ModelAndView formPost(ModelAndView mav, @Valid @ModelAttribute Form form,
BindingResult result) {
//Überprüfen Sie die Validierung
if (result.hasFieldErrors()) {
mav.addObject("errors", result.getFieldErrors());
mav.addObject("form", form);
mav.setViewName("demoForm");
return mav;
}
//Formularwert speichern
formService.saveData(form);
mav.setViewName("ok");
return mav;
}
}
Darüber hinaus lautet die zum Senden und Empfangen von Formularen verwendete Formularklasse wie folgt. Der Name wird mit der Annotation @NotBlank überprüft.
Form.java
@Getter
@Setter
public class Form {
@NotBlank(message = "Der Name ist ein erforderliches Element.")
private String name;
}
Beim Testen des Spring MVC Controllers gibt es einige Versprechen. Bereiten Sie sie also zuerst vor. Ich werde den detaillierten Test in den folgenden Abschnitten beschreiben, aber ich bin beunruhigt über einen unerwarteten Fehler, wenn diese Vorbereitung nicht korrekt durchgeführt wird. (Ich habe Stunden damit verschwendet.)
Erstens, weil es notwendig ist, die DI-Funktion von Spring auch auf Junit auszuführen Fügen Sie der Testklasse die Anmerkungen @Runwith (..) und @SpringBootTest hinzu.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class DemoControllerTest {
Registrieren Sie die zu testende Klasse im DI-Container mit @Autowired. Bereiten Sie sich darauf vor, das Verhalten von Feder-MVC mit MockMvcBuilders.standaloneSetup (...) zu reproduzieren. Die Annotation @Before wird hinzugefügt, da sie vor jedem @Test erfolgt. Danach wird diese mockMvc-Instanz verwendet, um eine virtuelle Anforderung zu generieren und einen Test auszuführen.
private MockMvc mockMvc;
@Autowired
DemoController target;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(target).build();
}
mockMVC wurde auf der Website hier ausführlich erläutert.
Der bisherige Code lautet wie folgt.
DemoController
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class DemoControllerTest {
private MockMvc mockMvc;
@Autowired
DemoController target;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(target).build();
}
}
Schreiben Sie zunächst einen Test für die home () -Methode, der eine Ansicht zeichnet, indem Sie eine Nachricht in ein Modell mit der GET-Methode nach / home packen. Die zu testenden Punkte sind wie folgt.
Schauen wir sie uns der Reihe nach an.
Führen Sie die Anforderung mit der Ausführung von mockMvc aus.
python
mockMvc.perform(Methodenname("Angegebene URL"))
Testen Sie dann die Antwort mit der andExcept-Methode.
python
.andExpect(Testgegenstände)
Da wir dieses Mal den HTTP-Statuscode testen, verwenden wir status (). Der Statuscode 200 kann mit status () getestet werden. IsOk. Ein typischer Statuscode kann wie folgt bestimmt werden.
Status | Methode |
---|---|
200 | status().isOk() |
308 | status().isPermanentRedirect() |
404 | status().isNotFound() |
403 | status().isForbidden() |
503 | status().isServiceUnavailable() |
Der bisherige Code lautet wie folgt.
DemoControllerTest.java
@Test
public void getIndexTest() throws Exception {
// when
mockMvc.perform(get("/home"))
.andExpect(status().isOk());
}
Überprüfen Sie, ob "/ home" index.html zurückgibt. Verwenden Sie view (). Name (), um die Ansicht zu beurteilen.
.andExpect(view().name(Vorlagenname))
Wenn hinzugefügt, wird es wie folgt sein.
DemoControllerTest.java
@Test
public void getIndexTest() throws Exception {
// when
mockMvc.perform(get("/home"))
.andExpect(status().isOk())
.andExpect(view().name("index"));
}
Testen Sie als Nächstes den Status des Modells, um festzustellen, ob die in der Ansicht verwendeten Variablen korrekt im Modell gepackt sind. Verwenden Sie model (). Attribute (), um zu testen, ob Sie eine Variable zur Ansicht übergeben
python
model().attribute(Variablennamen,Wert)
Dieses Mal ist die Variable namens message mit hallo world gefüllt Es wird wie folgt sein.
python
@Test
public void getIndexTest() throws Exception {
// when
mockMvc.perform(get("/home"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andExpect(model().attribute("message", "hello world"));
}
Es kann andere Möglichkeiten geben, dies zu tun, aber sobald der Indextest in Ordnung ist.
Die Formularmethode packt die initialisierte formBean in ein Modell und zeigt demoForm.html an. Wenn Sie jedoch nur die Ansicht des Formulars zurückgeben, ist diese dieselbe wie zuvor. Testen Sie daher, ob Sie den Anfangswert im Namensfeld des Formulars festlegen können.
DemoController.java
form.setName("hoge");
mav.addObject("form", form);
Der Inhalt des an das Modell übergebenen Objekts kann ermittelt werden, indem der Rückgabewert der Anforderung mit mockMvc.perform (). AndReturn () abgerufen wird. Empfangen Sie das Anforderungsergebnis MvcResult mit .andReturn und rufen Sie von dort aus die Ansicht und das Modell mit getModelAndView ab. Darüber hinaus wird das Modell von getModel erfasst und der Wert von "form" wird von der get-Methode erfasst. Beachten Sie, dass der Rückgabewert von get () vom Typ object ist. Lassen Sie uns ihn also mit (Form) umwandeln. Zusammenfassend sieht es wie folgt aus.
DemoControllerTest
@Test
public void getFormTest() throws Exception {
// when
MvcResult result = mockMvc.perform(get("/form"))
.andExpect(status().isOk())
.andExpect(view().name("demoForm"))
.andReturn();
//Den Wert des im Modell gepackten Formulars erhalten Sie hier
Form resultForm = (Form) result.getModelAndView().getModel().get("form");
// then
assertEquals(resultForm.getName(),"hoge");
}
Testen Sie abschließend die formPost-Methode. Die formPost-Methode empfängt den Eingabewert des Formulars in der Post-Anfrage von demoform.html und empfängt ihn. Wenn Sie eine Validierung durchführen und keine Erroll vorliegt Es ruft FormService.saveData auf, speichert den Inhalt des Formulars und ruft ok.html auf. Da der Vorgang kompliziert ist, schreiben Sie die zu testenden Elemente auf.
Schauen wir uns jeden an.
Zuerst den Test, wenn ein Validierungsfehler vorliegt. Lassen Sie uns dazu einen Validierungsfehler auslösen. Da der Wert von name @NotBlank ist, tritt automatisch ein Fehler auf, wenn nichts angegeben wird. Fügen Sie hier explizit ein leeres Zeichen in den Namen ein. Verwenden Sie .param () oder .flashAttr, um Werte für die Anforderungsparameter einzugeben.
Im Fall von param,
// form.Beim Einfügen von Hoge in den Namen
// mockMvc.perform(post("URL-Name").param(Parametername,Wert))
mockMvc.perform(post("/form").param("name", "hoge"))
Bei Verwendung von flashAttr
// form.Beim Einfügen von Hoge in den Namen
// mockMvc.perform(post("URL-Name").flashAttr(Parametername,Objekt))
Form form = new Form()
form.setName("hoge")
mockMvc.perform((post("/form")).flashAttr("form",form))
Dieses Mal werden wir mit flashAttr testen. Ich teste, ob ein Validierungsfehler angezeigt wird, und zeige eine demoForm-Ansicht an.
Die Tatsache, dass ein Fehler aufgetreten ist, ist ...
model().hasError()
Es wird beurteilt von.
@Test
public void postFormTestInValid() throws Exception {
// given
Form form = new Form();
form.setName("");
// when
mockMvc.perform((post("/form")).flashAttr("form",form))
.andExpect(model().hasErrors())
.andExpect(model().attribute("form", form))
.andExpect(view().name("demoForm"));
}
Testen Sie dann, ob kein Validierungsfehler auftritt. Der Artikel, den ich hier testen möchte, ist
Es gibt zwei. Ob der angegebene HTML-Code zurückgegeben werden soll, wird im vorherigen Abschnitt erläutert Beschreibt, wie Sie testen, ob Sie die angegebene Methode (formService.saveData) aufrufen.
Das erste, was zu tun ist, ist den Zieldienst zu verspotten. Verwenden Sie in springMVC @MockBean anstelle von @Mock. Sie können eine Klasse verspotten, die @Autowired ist.
Außerdem werden Klassen mit der Annotation @MockBean automatisch ausgeführt Es wird verspottet, wenn die Klasse @Autowired (in diesem Fall DemoController) in der Testklasse ausgeführt wird. Fügen wir also @MockBean vor dem @ Autowired DemoController-Ziel hinzu.
・
・
private MockMvc mockMvc;
//hinzufügen
@MockBean
FormService mockFormService;
@Autowired
private DemoController target;
・
・
Anschließend wird die Verifizierungsmethode von Mockit verwendet, um den Nutzungsstatus des verspotteten Objekts zu bestimmen. Die folgenden Tests zeigen, dass formService.saveData einmal mit einer Instanz namens form als Argument aufgerufen wird.
// verify(Scheinobjektname,Anzahl der Verwendungen).Methodenname ・(Streit);
verify(mockFormService, times(1)).saveData(form);
Der gesamte Testcode ist unten. In form.name wird ein Wert festgelegt, um das Auftreten eines Fehlers zu verhindern.
@Test
public void postFormTestValid() throws Exception {
// given
Form form = new Form();
form.setName("fuga");
// when
mockMvc.perform((post("/form")).flashAttr("form", form))
.andExpect(model().hasNoErrors())
.andExpect(model().attribute("form", form))
.andExpect(view().name("ok"));
// then
verify(mockFormService, times(1)).saveData(form);
}
Der endgültige Code ist unten. Die Abdeckung von DemoController.java beträgt jetzt sowohl für die Methode als auch für die Zeile 100%.
DemoControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class DemoControllerTest {
private MockMvc mockMvc;
@MockBean
FormService mockFormService;
@Autowired
private DemoController target;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(target).build();
}
@Test
public void getIndexTest() throws Exception {
// when
mockMvc.perform(get("/home"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andExpect(model().attribute("message", "hello world"));
}
@Test
public void getFormTest() throws Exception {
// when
MvcResult result = mockMvc.perform(get("/form"))
.andExpect(status().isOk())
.andExpect(view().name("demoForm"))
.andReturn();
Form resultForm = (Form) result.getModelAndView().getModel().get("form");
// then
assertEquals(resultForm.getName(), "hoge");
}
@Test
public void postFormTestInValid() throws Exception {
// given
Form form = new Form();
form.setName("");
// when
mockMvc.perform((post("/form")).flashAttr("form", form))
.andExpect(model().hasErrors())
.andExpect(model().attribute("form", form))
.andExpect(view().name("demoForm"));
}
@Test
public void postFormTestValid() throws Exception {
// given
Form form = new Form();
form.setName("hoge");
// when
mockMvc.perform((post("/form")).flashAttr("form", form))
.andExpect(model().hasNoErrors())
.andExpect(model().attribute("form", form))
.andExpect(view().name("ok"));
// then
verify(mockFormService, times(1)).saveData(form);
}
}
Ich bin immer noch zuversichtlich, dass dies nicht korrekt ist. Ich hoffe, es hilft Menschen, die genauso besorgt sind, Tests zu schreiben wie sie.
https://qiita.com/NetPenguin/items/0e06779ecdd48d24a5db https://ito-u-oti.com/post-129/ http://blog.okazuki.jp/entry/2015/07/14/205627 https://terasolunaorg.github.io/guideline/5.4.1.RELEASE/ja/UnitTest/ImplementsOfUnitTest/UsageOfLibraryForTest.html
Recommended Posts