18.2. Testing Files
The code to test things like file existence and file size is simple, but the more code we write, and the more parts each code statement has, the more likely we are not only to mess up, but to miscommunicate our intent to the maintenance programmer.
We could test for file existence very easily. We use the -e file test operator in the ok( ) function from Test::More. That works just fine.
use Test::More 'no_plan'; ok( -e 'minnow.db' );
Well, it works just fine if that's what we meant to test, but nothing in that code tells anyone what we meant to do. What if we wanted to ensure the file did not exist before we started testing? The code for that is a difference of one character.
use Test::More 'no_plan'; ok( ! -e 'minnow.db' );
We could add a code comment, but as you probably already know, most code comments seem to assume that you already know what's supposed to happen. Does this comment let you know which of the two situations we want? Should we pass the test if the file is there?
use Test::More 'no_plan'; # test if the file is there ok( ! -e 'minnow.db' );
The Test::File module, written by brian, encapsulates intent in the name of the function. If we want the test to pass when the file is there, we use file_exists_ok.
use Test::More 'no_plan'; use Test::File; file_exists_ok( 'minnow.db' );
If we want the test to pass when the file is not there, we use file_not_exists_ok.
use Test::More 'no_plan'; use Test::File; file_not_exists_ok( 'minnow.db' );
That's a simple example, but the module has many other functions that follow the same naming scheme: the first part of the name tells you what the function checks (file_exists) and the last part tells you what happens if that's true (_ok). It's a lot harder to miscommunicate the intent when we have to type it out.
use Test::More 'no_plan'; use Test::File; my $file = 'minnow.db'; file_exists_ok( $file ); file_not_empty_ok( $file ); file_readable_ok( $file ); file_min_size_ok( $file, 500 ); file_mode_is( $file, 0775 );
So, not only do the explicit function names communicate intent, but they also contribute to parallel structure in the code.