@@ -34,17 +34,21 @@ async fn main() {
34
34
. init ( ) ;
35
35
36
36
// build our application with a route
37
- let app = Router :: new ( ) . route ( "/" , get ( handler ) ) ;
37
+ let app = app ( ) ;
38
38
39
39
// run it
40
40
let listener = TcpListener :: bind ( "127.0.0.1:3000" ) . await . unwrap ( ) ;
41
41
tracing:: debug!( "listening on {}" , listener. local_addr( ) . unwrap( ) ) ;
42
42
axum:: serve ( listener, app) . await . unwrap ( ) ;
43
43
}
44
44
45
+ fn app ( ) -> Router {
46
+ Router :: new ( ) . route ( "/" , get ( handler) )
47
+ }
48
+
45
49
#[ derive( Debug , Deserialize , Validate ) ]
46
50
pub struct NameInput {
47
- #[ validate( length( min = 1 , message = "Can not be empty" ) ) ]
51
+ #[ validate( length( min = 2 , message = "Can not be empty" ) ) ]
48
52
pub name : String ,
49
53
}
50
54
@@ -91,3 +95,83 @@ impl IntoResponse for ServerError {
91
95
. into_response ( )
92
96
}
93
97
}
98
+
99
+ #[ cfg( test) ]
100
+ mod tests {
101
+ use super :: * ;
102
+ use axum:: {
103
+ body:: Body ,
104
+ http:: { Request , StatusCode } ,
105
+ } ;
106
+ use http_body_util:: BodyExt ;
107
+ use tower:: ServiceExt ;
108
+
109
+ async fn get_html ( response : Response < Body > ) -> String {
110
+ let body = response. into_body ( ) ;
111
+ let bytes = body. collect ( ) . await . unwrap ( ) . to_bytes ( ) ;
112
+ String :: from_utf8 ( bytes. to_vec ( ) ) . unwrap ( )
113
+ }
114
+
115
+ #[ tokio:: test]
116
+ async fn test_no_param ( ) {
117
+ let response = app ( )
118
+ . oneshot ( Request :: builder ( ) . uri ( "/" ) . body ( Body :: empty ( ) ) . unwrap ( ) )
119
+ . await
120
+ . unwrap ( ) ;
121
+
122
+ assert_eq ! ( response. status( ) , StatusCode :: BAD_REQUEST ) ;
123
+ let html = get_html ( response) . await ;
124
+ assert_eq ! ( html, "Failed to deserialize form: missing field `name`" ) ;
125
+ }
126
+
127
+ #[ tokio:: test]
128
+ async fn test_with_param_without_value ( ) {
129
+ let response = app ( )
130
+ . oneshot (
131
+ Request :: builder ( )
132
+ . uri ( "/?name=" )
133
+ . body ( Body :: empty ( ) )
134
+ . unwrap ( ) ,
135
+ )
136
+ . await
137
+ . unwrap ( ) ;
138
+
139
+ assert_eq ! ( response. status( ) , StatusCode :: BAD_REQUEST ) ;
140
+ let html = get_html ( response) . await ;
141
+ assert_eq ! ( html, "Input validation error: [name: Can not be empty]" ) ;
142
+ }
143
+
144
+ #[ tokio:: test]
145
+ async fn test_with_param_with_short_value ( ) {
146
+ let response = app ( )
147
+ . oneshot (
148
+ Request :: builder ( )
149
+ . uri ( "/?name=X" )
150
+ . body ( Body :: empty ( ) )
151
+ . unwrap ( ) ,
152
+ )
153
+ . await
154
+ . unwrap ( ) ;
155
+
156
+ assert_eq ! ( response. status( ) , StatusCode :: BAD_REQUEST ) ;
157
+ let html = get_html ( response) . await ;
158
+ assert_eq ! ( html, "Input validation error: [name: Can not be empty]" ) ;
159
+ }
160
+
161
+ #[ tokio:: test]
162
+ async fn test_with_param_and_value ( ) {
163
+ let response = app ( )
164
+ . oneshot (
165
+ Request :: builder ( )
166
+ . uri ( "/?name=LT" )
167
+ . body ( Body :: empty ( ) )
168
+ . unwrap ( ) ,
169
+ )
170
+ . await
171
+ . unwrap ( ) ;
172
+
173
+ assert_eq ! ( response. status( ) , StatusCode :: OK ) ;
174
+ let html = get_html ( response) . await ;
175
+ assert_eq ! ( html, "<h1>Hello, LT!</h1>" ) ;
176
+ }
177
+ }
0 commit comments