Unit Testing File Modifications

Unit Testing File Modifications

You're talking about testing too much at once. If you start trying to attack a testing problem by saying "Let's verify that it modifies its environment correctly", you're doomed to failure. Environments have dozens, maybe even millions of potential variations.

Instead, look at the pieces ("units") of your program. For example, are you going to have a function that determines where the files are that have to be written? What are the inputs to that function? Perhaps an environment variable, perhaps some values read from a config file? Test that function, and don't actually do anything that modifies the filesystem. Don't pass it "realistic" values, pass it values that are easy to verify against. Make a temporary directory, populate it with files in your test's setUp method.

Then test the code that writes the files. Just make sure it's writing the right contents file contents. Don't even write to a real filesystem! You don't need to make "fake" file objects for this, just use Python's handy StringIO modules; they're "real" implementations of the "file" interface, they're just not the ones that your program is actually going to be writing to.

Ultimately you will have to test the final, everything-is-actually-hooked-up-for-real top-level function that passes the real environment variable and the real config file and puts everything together. But don't worry about that to get started. For one thing, you will start picking up tricks as you write individual tests for smaller functions and creating test mocks, fakes, and stubs will become second nature to you. For another: even if you can't quite figure out how to test that one function call, you will have a very high level of confidence that everything which it is calling works perfectly. Also, you'll notice that test-driven development forces you to make your APIs clearer and more flexible. For example: it's much easier to test something that calls an open() method on an object that came from somewhere abstract, than to test something that calls os.open on a string that you pass it. The open method is flexible; it can be faked, it can be implemented differently, but a string is a string and os.open doesn't give you any leeway to catch what methods are called on it.

You can also build testing tools to make repetitive tasks easy. For example, twisted provides facilities for creating temporary files for testing built right into its testing tool. It's not uncommon for testing tools or larger projects with their own test libraries to have functionality like this.

How to unit test function that modifies a file

  1. Test Read() first using pre-existing test files.
  2. Now that you know it works, use Read() to test Write().

Best Practices are less about being the best practice and more about avoiding bad practices. Bad practices like coupling too much code together in a single test such that you can't tell where the problem lies and such that multiple bugs can interact to cause failure. Unit tests, among other purposes, try to avoid coupling. But if you try to follow Best Practices as dogma, and concern yourself too much with what category of test everything is, you'll wind up doing some bad practices just to try and follow the Best Practices.

Reading and writing files are inherently coupled, writing isn't much use unless you can read it, and you have them in the same class so it's not an external dependency. The trick is to write your tests such that Read() and Write() bugs can't interact to cause a false positive. For example, if you did something like this:

file = Temp.file
content = Read(file)
Write(file, content)

assert_eq( Read(file), content )

Then if Read(file) has a bug which occasionally returns an empty string, and Write(file, content) has a bug which just wipes the file, you'll get a false positive from the assert. Whereas if you wrote it like so:

file = Temp.file
content = "The quick brown fox jumped over the lazy grey dog.\n"
Write(file, content)
assert_eq( Read(file), content )

Bugs in Read() and Write() cannot lead to a false positive (unless you're in a pass-by-reference language, in which case content should be declared constant). Though they can interact, which leads us to the next bit.


You can test Read() without Write(), so do that first to be assured Read() works before using it to test Write(). Pre-generate a bunch of interesting files to exercise Read(): Unicode, empty files, big files, special files, etc...

# Pardon my mish-mash prototype language
tests = {
empty: "",
just_newline: "\n",
simple: "This test is not metal.",
simple_unicode: "†Hîß †É߆ Îß µé†å¬¡¡¡ br>}

for (file, want) in tests {
assert_eq( Read(file), want, "Read(#{file})" )
}

If your test suite features ordering, make sure the Read() tests run before the Write() tests. Now if you run your tests and Write() fails you can be fairly certain it's not because Read() failed.

Once you're satisfied Read() works, you can safely use it to test Write().


There are always couplings in your code and tests, without them you can't get anything done. For example, if Temp.file has a bug where it doesn't always an empty temp file that can introduce bugs.

The trick isn't to eliminate all couplings, the trick is to minimize them. With regard to testing, strive to test one thing at a time. Since the Temp class was presumably well-tested when it was installed, and because it's a standard and very well used class, it's safe to rely on it in your tests. In this way you build up an ever-increasing foundation of well tested code to build and test more code on top of.

How to modify a text file's Date modified property without affecting the content using c++?

From code

If you need to set if from your code itself, see Fredrik Mörk's answer (the accepted answer) on SuperUser site:

Using copy command to just change the time and date of a file on Windows OS

Text copy of Fredrik Mörk's answer :

If you feel like coding it yourself, .NET offers the File.SetLastAccessTime, File.SetCreationTime and File.SetLastWriteTime methods.

From external tool

If you need to set it from an outside tool, such as cmd.exe, See Gish Domains' answer on SuperUser site:

Using copy command to just change the time and date of a file on Windows OS

Text copy of link:

If you want to touch the date stamp of a file using windows, use the following command at the command prompt:

copy /b filename.ext +,,

(where filename.ext is your file's name). The +,, is a special flag to copy telling it to simply update the date/time on the file:

  • Changing the time and date of a file

If you want to assign the current time and date to a file without modifying the file, use the following syntax:

copy /b Source+,,

The commas indicate the omission of the Destination parameter.

Edit based on comments by Lumi and Justin: put this in a batch file, eg. touch.cmd

@COPY /B %1+,, %1

This works even if the file is not in the current directory (tested on Windows 7).

Unit testing code with a file system dependency

There's really nothing wrong with this, it's just a question of whether you call it a unit test or an integration test. You just have to make sure that if you do interact with the file system, there are no unintended side effects. Specifically, make sure that you clean up after youself -- delete any temporary files you created -- and that you don't accidentally overwrite an existing file that happened to have the same filename as a temporary file you were using. Always use relative paths and not absolute paths.

It would also be a good idea to chdir() into a temporary directory before running your test, and chdir() back afterwards.

Unit Testing File I/O

Check out Tutorial to TDD using Rhino Mocks and SystemWrapper.

SystemWrapper wraps many of System.IO classes including File, FileInfo, Directory, DirectoryInfo, ... . You can see the complete list.

In this tutorial I'm showing how to do testing with MbUnit but it's exactly the same for NUnit.

Your test is going to look something like this:

[Test]
public void When_try_to_create_directory_that_already_exists_return_false()
{
var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
directoryInfoStub.Stub(x => x.Exists).Return(true);
Assert.AreEqual(false, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));

directoryInfoStub.AssertWasNotCalled(x => x.Create());
}

How to test that a file is left unchanged?

You can use DI to mock your filewriter. This way you do not need the file at all, only check if the write function is called and you know if the file was modified.

maven test failing as file modified timings get updated

mvn clean is getting rid of everything in your target/ directory before running the tests, and repopulating it. Hence, the timestamp will change every run. But this also will be the case for an initial (clean) checkout of the project, which you should be doing before any release build, so ... this is a pretty normal thing to be happening.

However, I agree with all the comments -- your test (not posted) doesn't make a lot of sense. If you want to have your test check a file with a relative timestamp, then e.g. set the timestamp on the file to 4 minutes ago and confirm it's not loaded, then set it to 6 minutes ago and confirm it's loaded. You can set the last-modified value on your test file from within the test. This is much more reliable than relying on something in the test execution system (maven) itself, especially if you generate the test file as part of the test (a good idea)

Also: if you only want to load data files older than a certain time, then I doubt you really want to have those be classpath resources. They should probably be loaded from some other known location. I suspect you are trying to solve some problem with cleverness that would be better solved by something from, e.g., https://commons.apache.org/

Is there a way to start unit tests which related only to changed code?

You might like to checkout pytest-incremental:

The idea is to execute your tests faster by executing not all of them but only the “required” ones.

Install via pypi:

pip install pytest-incremental

Usage:

$ py.test --inc

I think it does what you are looking for, it "looks for imports recursively to find dependencies (using AST)" and runs only the changed tests.

change directory of generated unit test files

I just confirmed your problem, When adding more tests for the file I moved i just got the first 2 lines of the file generated.

I'm guessing the wizard just doesn't know how to look in subfolders to know what file to add it to, but errors when trying to generate a second class of the same name. (I'd guess if you rename any of the test files but leave them in the root it would also have this problem, but I didn't test this idea)

So I don't think there is anyway around it if you want to continue to use the wizard. You should be able to move it to the root, use the wizard, and move it back right. That's the best option I can think of.

I'm thinking the test abilities were greatly improved in VS2010, I have not used that but maybe the fixed it for that version...

This answer offers a solution, using a 3rd party code template.



Related Topics



Leave a reply



Submit