Skip to content

Commit a1bf2cd

Browse files
authored
docs(testing): include middleware tests (#370)
1 parent 1669cf9 commit a1bf2cd

File tree

1 file changed

+126
-4
lines changed

1 file changed

+126
-4
lines changed

docs/docs/basics/testing.md

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,27 @@ sidebar_position: 5
44

55
# Testing 🧪
66

7-
In Dart Frog, we can unit test our route handlers and middleware effectively because they are plain functions.
7+
In Dart Frog, we can effectively unit test our route handlers and middleware using [`package:test`](https://pub.dev/packages/test) and [`package:mocktail`](https://pub.dev/packages/mocktail).
88

9-
For example, we can test our route handler above using `package:test`:
9+
## Route Handlers 🚏
10+
11+
Testing route handlers is pretty straightforward and doesn't require any new concepts because a route handler is just a plain Dart function.
12+
13+
### Basics
14+
15+
Let's take a look at how we can test the following route handler:
16+
17+
```dart
18+
import 'package:dart_frog/dart_frog.dart';
19+
20+
Response onRequest(RequestContext context) {
21+
return Response(body: 'Hello World');
22+
}
23+
```
24+
25+
In the above handler, we're simply returning a `200` response with `'Hello World'` in the response body.
26+
27+
To test this, we can import our route handler, create a mock `RequestContext` using `package:mocktail`, and invoke `onRequest` with the mock request context to get a `Response`. Then, we can assert that the response is what we expect. In this case, we're checking the `statusCode` and response `body` to ensure that the response is a `200` and the body equals `'Hello World'`.
1028

1129
```dart
1230
import 'dart:io';
@@ -22,15 +40,119 @@ class _MockRequestContext extends Mock implements RequestContext {}
2240
void main() {
2341
group('GET /', () {
2442
test('responds with a 200 and greeting.', () async {
25-
const greeting = 'Hello World!';
43+
// Arrange
44+
final context = _MockRequestContext();
45+
46+
// Act
47+
final response = route.onRequest(context);
48+
49+
// Assert
50+
expect(response.statusCode, equals(HttpStatus.ok));
51+
expect(response.body(), completion(equals('Hello World')));
52+
});
53+
});
54+
}
55+
```
56+
57+
### Stubbing `context.read<T>`
58+
59+
Often times, your route handler won't be as simple. For example, it may resolve dependencies via the `RequestContext` like:
60+
61+
```dart
62+
import 'package:dart_frog/dart_frog.dart';
63+
64+
Response onRequest(RequestContext context) {
65+
final greeting = context.read<String>();
66+
return Response(body: greeting);
67+
}
68+
```
69+
70+
The steps to test the above route handler are the same as before. The only thing we need to add is a stub for `context.read`:
71+
72+
```dart
73+
import 'dart:io';
74+
75+
import 'package:dart_frog/dart_frog.dart';
76+
import 'package:mocktail/mocktail.dart';
77+
import 'package:test/test.dart';
78+
79+
import '../../routes/index.dart' as route;
80+
81+
class _MockRequestContext extends Mock implements RequestContext {}
82+
83+
void main() {
84+
group('GET /', () {
85+
test('responds with a 200 and greeting.', () async {
86+
// Arrange
87+
final greeting = 'Hello!';
2688
final context = _MockRequestContext();
2789
when(() => context.read<String>()).thenReturn(greeting);
90+
91+
// Act
2892
final response = route.onRequest(context);
93+
94+
// Assert
2995
expect(response.statusCode, equals(HttpStatus.ok));
3096
expect(response.body(), completion(equals(greeting)));
3197
});
3298
});
3399
}
34100
```
35101

36-
In the above test, we're using `package:mocktail` to create a mock `RequestContext` and stub the return value when calling `context.read<String>()`. Then, all we need to do is call `onRequest` with the mocked context and we can assert that the response is what we expect. In this case, we're checking the statusCode and response body to ensure that the response is a 200 with the provided greeting.
102+
## Middleware 🍔
103+
104+
Unit testing middleware is very similar to unit testing route handlers — they are both just dart functions after all!
105+
106+
### Basics
107+
108+
Let's take a look at a piece of middleware that provides a greeting to the `RequestContext` via the `provider` API:
109+
110+
```dart
111+
import 'package:dart_frog/dart_frog.dart';
112+
113+
Handler middleware(Handler handler) {
114+
return handler.use(provider<String>((_) => 'Hello World'));
115+
}
116+
```
117+
118+
We can unit test this piece of middleware in isolation using `package:test` and `package:mocktail` just like before.
119+
120+
To test this, we need to import our middleware, create a mock `RequestContext` using `package:mocktail`, apply our middleware to a dummy handler, and invoke the handler with a mock request context. Then, we can assert that the simple handler we applied the middleware to had access to the provided value.
121+
122+
```dart
123+
import 'package:dart_frog/dart_frog.dart';
124+
import 'package:mocktail/mocktail.dart';
125+
import 'package:test/test.dart';
126+
127+
import '../../routes/_middleware.dart';
128+
129+
class _MockRequestContext extends Mock implements RequestContext {}
130+
131+
void main() {
132+
group('middleware', () {
133+
test('provides greeting', () async {
134+
// Arrange
135+
String? greeting;
136+
final handler = middleware(
137+
(context) {
138+
greeting = context.read<String>();
139+
return Response(body: '');
140+
},
141+
);
142+
final request = Request.get(Uri.parse('http://localhost/'));
143+
final context = _MockRequestContext();
144+
when(() => context.request).thenReturn(request);
145+
146+
// Act
147+
await handler(context);
148+
149+
// Assert
150+
expect(greeting, equals('Hello World'));
151+
});
152+
});
153+
}
154+
```
155+
156+
:::info
157+
We are stubbing the `context.read` with a real `Request` object so that the `provider` is able to inject the value.
158+
:::

0 commit comments

Comments
 (0)