2017-10-17 78 views
1

我正在爲我的代碼編寫單元測試。現在我想測試放入表單的值是否正確保存在Controller中的變量中。依賴於這個模型屬性的測試都是正確的,失敗。因爲模型存在但是保持爲空,這意味着我以錯誤的方式從我的測試中發送了值。我如何讓我的測試包含輸入值以正確測試發佈方法?Spring/Thymeleaf單元測試:測試沒有正確發送模型的值

測試testPostValueInModel()失敗,一個AssertionError:

java.lang.AssertionError: Model attribute 'chosenTemp' does not exist 

我必須指出,我很新的這一切,所以如果有人有一個答案,請提供一些更多的代碼示例和解釋什麼是出錯了,所以我可以從我的錯誤中吸取教訓。謝謝。

這裏是我的測試類:

@RunWith(SpringRunner.class) 
@WebMvcTest(InvoerschermController.class) 
@AutoConfigureMockMvc 
public class InvoerschermTest { 
    @Autowired 
    private MockMvc mockMvc; 

    @Test 
    public void testCorrectModel() { 
     try { 
      this.mockMvc.perform(get("/invoer", "20")).andExpect(status().isOk()) 
        .andExpect(model().attributeExists("chosenTemp")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void testPost() { 
     try { 
      this.mockMvc.perform(post("/invoer", "20")).andExpect(status().isOk()) 
        .andExpect(view().name("invoerscherm")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void testPostValueInModel() { 
     try { 
      this.mockMvc.perform(post("/invoer", "20")).andExpect(status().isOk()) 
        .andExpect(model().attributeExists("chosenTemp")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

控制器:

@Controller 
public class InvoerschermController { 

    private String chosenTemp = "20"; 
    private static PostgresDatabase database; 
    private static Connection connection; 

    // Static initializer for the database 
    static { 
     database = new PostgresDatabase(); 
     connection = database.connectToDatabase(); 
    } 

    @GetMapping("/invoer") 
    public String invoer(Model model) { 
     // int newTemp = Integer.parseInt(getChosenTemp()); 
     chosenTemp = database.getTemperature(connection); 
     model.addAttribute("chosenTemp", getChosenTemp()); 
     return "invoerscherm"; 
    } 

    @PostMapping("/invoer") 
    public String addInputTemp(String chosenTemp, Model model) { 
     setChosenTemp(chosenTemp); 
     model.addAttribute("chosenTemp", getChosenTemp()); 

     try { 
      int newTemp = Integer.parseInt(getChosenTemp()); 
      database.setTemperature(connection, newTemp); 
     } catch (NumberFormatException nfe) { 
      System.err.println("Invalid number: " + nfe.getMessage()); 
     } 

     return "invoerscherm"; 
    } 

    public String getChosenTemp() { 
     return chosenTemp; 
    } 

    public void setChosenTemp(String chosenTemp) { 
     this.chosenTemp = chosenTemp; 
    } 
} 

的Thymeleaf:

所有的
<!DOCTYPE HTML> 
<html xmlns:th="http://www.thymeleaf.org"> 
<head th:include="fragments/template :: head"></head> 
<head> 
<title>Smart CV</title> 
</head> 
<body> 

    <nav th:replace="fragments/template :: header"></nav> 

    <div class="container"> 
     <div class="hero-unit"> 
      <h1>Temperatuur instellen</h1> 
     </div> 

     <form action="#" th:action="@{/invoer}" th:object="${invoerscherm}" 
      method="post"> 
      <div class="form-group"> 
       <label for="chosenTemp">Gewenste temperatuur:</label> <input 
        type="text" class="form-control" id="chosenTemp" name="chosenTemp" 
        autocomplete="off" th:value="${chosenTemp}" /> 
      </div> 

      <button type="submit" class="btn btn-default" name="submitKnop">Stel 
       in</button> 
     </form> 
    </div> 

    <nav th:replace="fragments/template :: footer"></nav> 
</body> 
</html> 
+0

您是否遇到異常或者只是測試失敗?你會得到什麼失敗的消息? –

+1

您的代碼有瑕疵。切勿將狀態存儲在單例中。你沒有映射請求參數,所以沒有什麼可以映射的。你不應該得到並緩存連接。你的'字符串selectedTemp'應該用'@RequestParam(「chosenTemp」)'註釋,你應該修復你的測試以傳入參數。 –

+0

@ 72Services我得到的異常'java.lang.AssertionError:模型屬性'chosenTemp'不存在' – Kailayla

回答

1

首先控制器是有缺陷的。你不應該保持局部狀態(試着想象一下,當3個用戶在同一時間提交會發生什麼情況chosenTemp領域,因爲只有InvoerschermController的單個實例。

你的方法參數應與@RequestParam("chosenTemp")被標註匹配形式要發送,你的測試也應該反映你發送一個名爲chosenTemp參數的事實。

首先控制器

@Controller 
public class InvoerschermController { 

    private static PostgresDatabase database; 
    private static Connection connection; 

    // Static initializer for the database 
    static { 
     database = new PostgresDatabase(); 
     connection = database.connectToDatabase(); 
    } 

    @GetMapping("/invoer") 
    public String invoer(Model model) { 
     Integer chosenTemp = database.getTemperature(connection); 
     model.addAttribute("chosenTemp", chosenTemp); 
     return "invoerscherm"; 
    } 

    @PostMapping("/invoer") 
    public String addInputTemp(@RequestParam("chosenTemp") Integer chosenTemp, Model model) { 
     model.addAttribute("chosenTemp", chosenTemp); 
      database.setTemperature(connection, chosenTemp); 
     return "invoerscherm"; 
    } 
} 

通知從String類型更改爲Integer春季將爲您做類型轉換,並注意到@RequestParam的加入。現在你的測試也應該反映這一點。

@RunWith(SpringRunner.class) 
@WebMvcTest(InvoerschermController.class) 
@AutoConfigureMockMvc 
public class InvoerschermTest { 
    @Autowired 
    private MockMvc mockMvc; 

    @Test 
    public void testCorrectModel() { 
     try { 
      this.mockMvc.perform(get("/invoer")).andExpect(status().isOk()) 
        .andExpect(model().attributeExists("chosenTemp")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void testPost() { 
     try { 
      this.mockMvc.perform(post("/invoer").param("chosenTemp", "20").andExpect(status().isOk()) 
        .andExpect(view().name("invoerscherm")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Test 
    public void testPostValueInModel() { 
     try { 
      this.mockMvc.perform(post("/invoer").param("chosenTemp", "20")).andExpect(status().isOk()) 
        .andExpect(model().attributeExists("chosenTemp")); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

請注意添加了.param("chosenTemp", "20")來添加具有該名稱的請求參數。

您的控制器仍然存在缺陷,因爲它不應該關心Connection,它們應該被封裝在您的Database類中。儘管您的測試現在可能有效,但由於使用了Thymeleaf和表單綁定,您的實際應用程序仍然會失敗。表單綁定期望鍵invoerScherm下的對象可用,並且該對象應具有名爲chosenTemp的屬性。你實際上缺少一個表單對象。所以你的控制器應該是什麼樣子。

首先你需要一個表單對象:

public class InvoerScherm { 
    private Integer chosenTemp; 
    public InvoerScherm() {} 
    public InvoerScherm(Integer temp) { this.chosenTemp=temp;} 
    // Here be getters/setters 
} 

然後讓你的控制器創建並使用它

@Controller 
public class InvoerschermController { 

    private static PostgresDatabase database; 
    private static Connection connection; 

    // Static initializer for the database 
    static { 
     database = new PostgresDatabase(); 
     connection = database.connectToDatabase(); 
    } 

    @GetMapping("/invoer") 
    public String invoer(Model model) { 
     Integer chosenTemp = database.getTemperature(connection); 
     InvoerScherm invoerScherm = new InvoerScherm(chosenTemp); 
     model.addAttribute("invoerScherm", invoerScherm); 
     return "invoerscherm"; 
    } 

    @PostMapping("/invoer") 
    public String addInputTemp(@ModelAttribute InvoerScherm invoerScherm, Model model) { 
      database.setTemperature(connection, invoerScherm.getChosenTemp()); 
     return "invoerscherm"; 
    } 
} 

Ofcourse現在你的測試會再次失敗,但我這個任務留給你。