views:

219

answers:

4

I am writing a "Total Commander" like application in Java. There is quite obvious file system dependency here.

I want to unit test it. I created directory structure for test purposes, I keep it in known location in SVN repository. It works great so far.

Now, I have a method that should ignore hidden files. How can I go about this? Can I mark file hidden in the SVN somehow?

Other solution would be to make one of the files hidden in the build script before running tests, but I'm afraid this would mark file as modified and always show in a commit dialog.

Any suggestions?

+10  A: 

I would put all the initialization of a test directory into the tests themselves. And such a case would be simple:

  • create a directory
  • put some hidden and visible files into it
  • test
  • tear down by removing the directory
artemb
+1. Test files do not belong to source control.
ChssPly76
How could I make this in JUnit 4? Is there some way to set this up before all tests and tear down when all tests are finished?
Ula Krukar
Look at `@BeforeClass` and `@AfterClass`
Rorick
It's better to create the desired directory structure per-test, not per-suite, to minimize the risk of hidden dependencies between tests. Shared stated is evil in unit tests
artemb
Yes, you're right. But I'm assured that those test will be slow sooner or later =) For beginning, using test-level setup presumably better.
Rorick
Yes. If it can be automated, it is the responsibility of the test itself. Alternatively, you could use Mocks and thus don't need any real files at all.
wierob
@ChssPly76: I disagree. If you're writing acceptance / integration tests, you need to have the test data - and it should be stored with the tests (i.e. in the source control), or generated (by code that is stored in the source control).
Assaf Stone
+2  A: 

I would prefer to abstract file system, so that my unit-test wouldn't require access to real file system. Of course, this abstraction layer must be tested with real file system, but this allow you to reduce dependency on it.

As for storing hidden files in SVN, I second artemb. You should create all files necessary to test in JUnit set up. Presumably, you should prefer setup per test method (@Before and @After). But if you encounter test slowness problems, have a look at @BeforeClass and @AfterClass. I consider they can be used with test suites too.

Rorick
A: 

Hello,

artemb's answer is correct, you can use @Before and @After to create and remove your structure for each test.

Here is some code I use to create a new directory with some files in it, it will create the directory in the systems temp dir, this is important because depending on the machine your tests will run on, you may will not be allowed to create files or dirs somewhere else. (I had to write this code to allow my tests to be executed on our linux integration machine...)

    final String tempdir = System.getProperty("java.io.tmpdir");
    final String dirname = Long.toHexString(System.currentTimeMillis());
    final File dir = new File(tempdir, dirname);
    dir.deleteOnExit();
    dir.mkdir();
    final String path = dir.getAbsolutePath();
    assertTrue(dir.exists());
    // pre condition, the directory is empty
    assertTrue(dir.list().length == 0);

    // create temp files in the directory
    final int nbFiles = 3;
    for (int i = 0; i < nbFiles; i++) {
        (File.createTempFile("test", ".txt", dir)).deleteOnExit();
    }

BTW you will have to know on what platform you run to be able to create hiden files...

pgras
+2  A: 

Essentially, accessing the file system is a big no-no when unit testing. For starters, these tests are slow(er) than your in-system tests, thus reducing the likelihood of you running your tests at a high frequency (such as with every compilation).

Much better if you use an adapter-pattern to abstract away the access to the file system. I'm a .NET developer so my example will be in C#, but I expect you to be able to translate it simply enough:

public class MyManager
{
    private readonly IFileAdapter _fileAdapter;
    public MyManager(IFileAdapter fileAdapter)
    {
        _fileAdapter = fileAdapter;
    }
}

public interface IFileAdapter
{
    public FileStream Open(string fileName);
    public string ReadLine(FileStream fileStream);
    // More methods...
}

public class FileAdapter : IFileAdapter
{
    public FileStream Open(string fileName)
    {
        return System.Io.File.Open(fileName);
    }

    public string ReadLine(FileStream fileStream)
    {
        return File.Open(fileStream);
    }
}

Now, as usual, you can mock the file system, as you would any other class, supplying the returned results. Remember - you are not testing Java's IO classes it is assumed that they work. You are only testing your classes (i.e. MyManager, in the example above).

Leave the tests that actually use the file system to your integration / acceptance tests.

Hope this helps, Assaf.

Assaf Stone
I did what you suggested, one problem though. I have classes responsible for GUI (layout of controls etc. One of them needs actual <code>java.io.File</code> to find system icon of the file. Is it OK to work on actual files, not the abstraction, in the GUI layer of the application? I am not going to unit test it anyway.
Ula Krukar
If you don't test the GUI layer, then you don't really need the abstraction of the File class. However, the logic required to find the file is something you might not want to have in the GUI layer - it is part of your problem Domain, if I understand what you mean. As such, I'd move it to the Business layer. And since you want to test the BL, you should use the adapter.HTH,Assaf.
Assaf Stone
I do need the abstraction, I used File throughout my whole code. Now, after abstracting it, I need it in two places: to initialize the application and find icons. Everything else, including any business logic, is done via abstraction.
Ula Krukar
I pretty much like to limit the GUI layer to having no logic whatsoever. This means my GUI layer typically has nothing more than pass-through calls to the presentation layer, display methods (i.e. MessageBox.Show("foo");) and initialization.As soon as I find myself putting any kind of logic (conditionals, loops, etc.) it gets promoted to the model, and is thus tested.Using that logic you can easily decide if you should abstract the File access to finding the icons and initializing the application.
Assaf Stone