http://qs321.pair.com?node_id=11121951


in reply to Re: Can Test::MockObject mock a file?
in thread Can Test::MockObject mock a file?

fancy_open opens a file, runs the contents through a while that chomps it, and prepends the lines with the string in the before option and/or appends the string in the after option. It returns an array.

So what I need is a file to open and manipulate. The contents of the file do not need to be spectacular, and I will probably use my favorite dummy list.

red orange yellow spring green teal cyan azure blue violet magenta pink white black gray

I am willing to use an actual file for the test, but I am unsure where to put it. Do I put it in the t directory with the test? Is it better to use a mock file instead? I would like to get this module's tests written first. I am finally learning how to write tests, so please bear with me for a short while?

My OS is Debian 10 (Buster); my perl versions are 5.28.1 local and 5.16.3 or 5.30.0 on web host depending on the shebang.

No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
Lady Aleena

Replies are listed 'Best First'.
Re^3: Can Test::MockObject mock a file?
by tobyink (Canon) on Sep 19, 2020 at 23:15 UTC

    I would suggest putting that file in your t/ directory, using FindBin to get the full path to your t/ directory, and then passing that path to your module.

      Done and thank you!

      Here is my test file. I hope I wrote it correctly, and it is well formed. All the tests passed.

      My OS is Debian 10 (Buster); my perl versions are 5.28.1 local and 5.16.3 or 5.30.0 on web host depending on the shebang.

      No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
      Lady Aleena

        You could make it less repetitive, but looks good apart from that.

        #!perl use strict; use warnings; use v5.10.0; use Test::More tests => "5"; use FindBin qw($Bin); BEGIN { use_ok( 'Fancy::Open', qw(fancy_open) ) or die "Fancy::Open is not available\n"; } diag( "Testing Fancy::Open $Fancy::Open::VERSION, Perl $], $^X" ); my $file = "$Bin/test-open.txt"; my @wanted = qw( red orange yellow spring green teal cyan azure blue violet magenta pink white black gray ); is_deeply( [ Fancy::Open::fancy_open($file) ], [ @wanted ], "testing a plain array" ); is_deeply( [ Fancy::Open::fancy_open($file, { 'before' => 'solid ' }) ], [ map "solid $_", @wanted ], "testing an array with before option" ); is_deeply( [ Fancy::Open::fancy_open($file, { 'after' => ' bead' }) ], [ map "$_ bead", @wanted ], "testing an array with after option" ); is_deeply( [ Fancy::Open::fancy_open($file, { 'before' => 'solid ', 'after' => +' bead' }) ], [ map "solid $_ bead", @wanted ], "testing an array with before and after options" ); done_testing();

        You might also want to test it on a file that ends with a "\n" and a file that doesn't end with a "\n", and see if the behaviour differs between them. Having checked your module, I don't think it will, but it might be useful to have a test for it, so you don't accidentally change that in the future without realizing it.

Re^3: Can Test::MockObject mock a file?
by davido (Cardinal) on Sep 20, 2020 at 04:38 UTC

    Your test script can use File::Temp to create a file for you that you write to, and that you then can read back in your test. Done correctly, the file will be removed on end of scope. I usually prefer creating a tempdir with a template such as testname-XXXXX. That way I can create any files I want within that directory, and it will get torn down on close of scope; I don't have to bother with temp files for each thing that needs a file, so long as I put everything ephemeral into the tempdir.

    A staunch unit-test advocate would say that unit tests shouldn't touch the filesystem unless they're specifically testing low level filesystem operations. It may be possible for your tests to open filehandles to in-memory files instead of touching the filesystem. The documentation for open discusses how to do this, I think. If it doesn't, then perlopentut would be the other place to look. But in short:

    my $in_string = "Hello world.\n"; my $out_string = ''; open my $infh, '<', \$in_string; open my $outfh, '>', \$out_string; while(<$infh>) { print $outfh "$.: $_"; } print $out_string; # prints 1: Hello world.\n

    So here I gave Perl a variable containing "Hello world.\n" and told it to treat it as a file, allowing $infh to stream through the pseudo-file. I also gave Perl an empty string for output, and printed the input file to the output file, with a line number prepended. Finally, I printed the contents of the output string, and it contained the contents of the input string, but with a line number prepended.

    This technique is great for tests, because it allows you to test in isolation of the filesystem. Later, you can independently test that when you create files (in a tempdir) they have the appropriate names, permissions, and owner.

    My preference is to test as much as possible in isolation of the filesystem, but then in more functional tests, also verify things like the characteristics of created files, and the ability to read the files we need to be able to read. That way I can do really fast testing of things like what contents are dumped to or read from files, but can also verify that I'm working effectively within the environment.


    Dave