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