Coverage for tests / test_forms_single_model.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1from typing import Annotated, Optional 1abcd

2 

3from fastapi import FastAPI, Form 1abcd

4from fastapi.testclient import TestClient 1abcd

5from pydantic import BaseModel, Field 1abcd

6 

7app = FastAPI() 1abcd

8 

9 

10class FormModel(BaseModel): 1abcd

11 username: str 1abcd

12 lastname: str 1abcd

13 age: Optional[int] = None 1abcd

14 tags: list[str] = ["foo", "bar"] 1abcd

15 alias_with: str = Field(alias="with", default="nothing") 1abcd

16 

17 

18class FormModelExtraAllow(BaseModel): 1abcd

19 param: str 1abcd

20 

21 model_config = {"extra": "allow"} 1abcd

22 

23 

24@app.post("/form/") 1abcd

25def post_form(user: Annotated[FormModel, Form()]): 1abcd

26 return user 1efghij

27 

28 

29@app.post("/form-extra-allow/") 1abcd

30def post_form_extra_allow(params: Annotated[FormModelExtraAllow, Form()]): 1abcd

31 return params 1klmnop

32 

33 

34client = TestClient(app) 1abcd

35 

36 

37def test_send_all_data(): 1abcd

38 response = client.post( 1fhj

39 "/form/", 

40 data={ 

41 "username": "Rick", 

42 "lastname": "Sanchez", 

43 "age": "70", 

44 "tags": ["plumbus", "citadel"], 

45 "with": "something", 

46 }, 

47 ) 

48 assert response.status_code == 200, response.text 1fhj

49 assert response.json() == { 1fhj

50 "username": "Rick", 

51 "lastname": "Sanchez", 

52 "age": 70, 

53 "tags": ["plumbus", "citadel"], 

54 "with": "something", 

55 } 

56 

57 

58def test_defaults(): 1abcd

59 response = client.post("/form/", data={"username": "Rick", "lastname": "Sanchez"}) 1egi

60 assert response.status_code == 200, response.text 1egi

61 assert response.json() == { 1egi

62 "username": "Rick", 

63 "lastname": "Sanchez", 

64 "age": None, 

65 "tags": ["foo", "bar"], 

66 "with": "nothing", 

67 } 

68 

69 

70def test_invalid_data(): 1abcd

71 response = client.post( 1qrs

72 "/form/", 

73 data={ 

74 "username": "Rick", 

75 "lastname": "Sanchez", 

76 "age": "seventy", 

77 "tags": ["plumbus", "citadel"], 

78 }, 

79 ) 

80 assert response.status_code == 422, response.text 1qrs

81 assert response.json() == { 1qrs

82 "detail": [ 

83 { 

84 "type": "int_parsing", 

85 "loc": ["body", "age"], 

86 "msg": "Input should be a valid integer, unable to parse string as an integer", 

87 "input": "seventy", 

88 } 

89 ] 

90 } 

91 

92 

93def test_no_data(): 1abcd

94 response = client.post("/form/") 1tuv

95 assert response.status_code == 422, response.text 1tuv

96 assert response.json() == { 1tuv

97 "detail": [ 

98 { 

99 "type": "missing", 

100 "loc": ["body", "username"], 

101 "msg": "Field required", 

102 "input": {"tags": ["foo", "bar"], "with": "nothing"}, 

103 }, 

104 { 

105 "type": "missing", 

106 "loc": ["body", "lastname"], 

107 "msg": "Field required", 

108 "input": {"tags": ["foo", "bar"], "with": "nothing"}, 

109 }, 

110 ] 

111 } 

112 

113 

114def test_extra_param_single(): 1abcd

115 response = client.post( 1lnp

116 "/form-extra-allow/", 

117 data={ 

118 "param": "123", 

119 "extra_param": "456", 

120 }, 

121 ) 

122 assert response.status_code == 200, response.text 1lnp

123 assert response.json() == { 1lnp

124 "param": "123", 

125 "extra_param": "456", 

126 } 

127 

128 

129def test_extra_param_list(): 1abcd

130 response = client.post( 1kmo

131 "/form-extra-allow/", 

132 data={ 

133 "param": "123", 

134 "extra_params": ["456", "789"], 

135 }, 

136 ) 

137 assert response.status_code == 200, response.text 1kmo

138 assert response.json() == { 1kmo

139 "param": "123", 

140 "extra_params": ["456", "789"], 

141 }