When I actually used my “real fake” HTTP test server (code-named plummbur_kruk), I found it wanting. Nothing too horrible, but it does need a few higher-level API methods. Since this is a server for running tests, I will, of course, write tests to verify the new features.
The new features include: (1) a way to create individual records, (2) a way to delete records, and (3) a guard to ensure that all data is removed when the test server restarts. All of this is possible already, but not easy. #1 and #2 are possible via
HttpRequest
calls. #3 is accomplished by simply removing the noSQL file.Since all of this is done in Dart, I can immediately try out the results in code that is using my library—before I have even published it to Dart Pub. Dart rocks.
The test for #1, creating records in the test DB, is:
test("can create records", (){
schedule(()=> Kruk.create('{"name": "Sandman"}'));
var ready = schedule(()=> get('${Kruk.SERVER_ROOT}/comics'));
schedule(() {
ready.then((json) {
var list = JSON.parse(json);
expect(list.first['name'], 'Sandman');
});
});
});
I am using the scheduled_test library here, which makes all asynchronous steps run in serial. In other words, it makes it much easier to keep track of what runs and when. In this case, I schedule the Kruk.create()
call to create a JSON record, then I schedule a GET from the server, and finally, I schedule the response from the server (the server is started by the same Bash script that runs the tests). This fails because there is no static
create()
method in Kruk
:CONSOLE MESSAGE: FAIL: The Mighty Kruk can create records Caught ScheduleError: | No static method 'create' declared in class 'Kruk'. | | NoSuchMethodError : method not found: 'create' | Receiver: Type: class 'Kruk' | Arguments: [...] Stack trace: | ../kruk_test.dart 23:26I make this pass by defining the
create()
method:class Kruk { static String SERVER_ROOT = 'http://localhost:31337'; // ... static Future<HttpRequest> create(String json) { return HttpRequest.request( '${SERVER_ROOT}/widgets', method: 'post', sendData: json ); } }Just like that, I have a nice
Kruk.create()
method to create records in my real fake server.The test and implementation for
Kruk.deleteAll()
is nearly identical to Kruk.create()
. The server supports this operation via a DELETE request to /widgets/ALL
. I could have made this more generic to support deletes of individual records, but I do not want to support this unless I know that it will be useful.Testing that the backing database is wiped in between restarts is a bit trickier. The methods in the
Kruk
class are all meant to be run in the browser. Code in the browser cannot access the file system, so I am relegated to placing the wiped test file into "dart:io" tests. Happily, I already have some of those, so I can just add this new test in there: group("Restarting", (){
test("removes file DB", (){
var server;
schedule(() {
Server.main().then((s) { server = s; });
});
var responseReady = schedule(() {
return new HttpClient().
postUrl(Uri.parse("http://localhost:31337/widgets")).
then((request) {
request.write('{"name": "Sandman"}');
return request.close();
});
});
schedule(() { server.close(); });
schedule(() {
return Server.main().then((s) { server = s; });
});
schedule(() {
expect(new File('test.db').existsSync(), isFalse);
});
schedule(() { server.close(); });
});
});
I am also using scheduled test in here. I have to create a number of schedules to start the server, write some data to ensure that the test database will exist, close the server, start up a new instance, and finally check that the database file has been removed.Getting this to pass is simpler: I tell the server to
removeDb()
when it closes:main() { return HttpServer.bind('127.0.0.1', 13317)..then((app) { app.listen((HttpRequest req) { /* ... */ }, onDone: removeDb); }); } removeDb() { var db_file = new File('test.db'); if (!db_file.existsSync()) return; db_file.deleteSync(); }With that, I have the tests passing for the features that I hoped to add. This seems a good stopping point for tonight. Unless I have a problem integrating these features back into the codebase that needs them, I will move on to other topics tomorrow.
Day #850
No comments:
Post a Comment