Design idempotent unit test - java

I'm designing unit tests for the following method:
public void loadFile(Path filename) throws IOException {
try {
// do something
} catch (RuntimeException ex) {
Files.move(filename, filename.resolveSibling("ERROR_" + filename.getFileName()));
return;
}
Files.delete(filename);
}
And I'm looking for a way of testing it without producing different results, since the input file is going to be either renamed or deleted after the execution test:
If RuntimeException takes place, file is renamed.
If execution goes as expected, file is deleted.
Either way, consecutive runs of the test will make it fail because file will be named different or it won't exist... How could I prevent that? Also, is there a way to verify Files#move(Path, Path, CopyOption...) and Files#delete(Path) were invoked?

I would recommend to use new #TempDir annotation from junit 5.
Docs:
When the end of the scope of a temporary directory is reached, i.e. when the test method or class has finished execution, JUnit will attempt to recursively delete all files and directories in the temporary directory and, finally, the temporary directory itself.
In that case you test cases will look as the next:
#Test
void loadsFileCorrectly(#TempDir Path temp) {
final Path file = temp.resolve("testable.file");
loadFile(file);
Assertions.assertTrue(Files.notExists(file));
}
#Test
void loadsFileWithException(#TempDir Path temp) {
final Path file = temp.resolve("testable.file");
loadFile(file);
Assertions.assertTrue(Files.exists(file.resolveSibling("ERROR_" + file.getFileName())));
}
In both scenarios, the created files will be automatically deleted after execution.

Related

How to get the file name from .properties file in java JUnit?

I have 8 test cases in which each test case makes use of a different file. How do I get the specific file from the .properties file which contains the path for the file(s). Some of the test cases are as shown below:
#Test
public void testIfColDataReadIsCorrect() throws FileNotFoundException{
obj.readExcelToGetData("D:/ExcelTestFiles/testExcelWithAllColData.xlsx");
rowObj= obj.getRowRecord();
assertEquals(rowObj.getName(), TEST_NAME);
assertEquals(rowObj.getId(), TEST_id);
assertEquals(rowObj.getDate(), TEST_DATE);
assertEquals(rowObj.getMessage(), TEST_MSG);
assertEquals(rowObj.getPage(), TEST_PAGE);
assertEquals(rowObj.getType(), TEST_TYPE);
assertEquals(rowObj.getLikeCount(),TEST_LIKECOUNT);
assertEquals(rowObj.getShareCount(), TEST_SHARECOUNT);
assertEquals(rowObj.getCommentCount(), TEST_COMMENTCOUNT);
}
#Test
public void testWhenNameColDoesNotExists() throws FileNotFoundException{
//FacebookDataExtraction obj= new FacebookDataExtraction();
//FacebookFields rowObj=new FacebookFields();
obj.readExcelToGetData("D:/ExcelTestFiles/testExcelWithNoNameCol.xlsx");
rowObj= obj.getRowRecord();
assertEquals(rowObj.getName(), null);
assertEquals(rowObj.getId(), TEST_id);
assertEquals(rowObj.getDate(), TEST_DATE);
assertEquals(rowObj.getMessage(), TEST_MSG);
assertEquals(rowObj.getPage(), TEST_PAGE);
assertEquals(rowObj.getType(), TEST_TYPE);
assertEquals(rowObj.getLikeCount(),TEST_LIKECOUNT);
assertEquals(rowObj.getShareCount(), TEST_SHARECOUNT);
assertEquals(rowObj.getCommentCount(), TEST_COMMENTCOUNT);
}
I think this is not the best practice to directly input the file path to the method readExcelToGetData(). After going through certain posts I found that the files can the put in .properties file and can be read from it. How do I get the specific file path in each test case?
You can load files from the classpath via a ClassLoader. E.g. : this.getClass().getClassLoader().getResourceAsStream("myFiles.properties");
So depending on your IDE, you might put the properties file into your source- or resources folder.
Running the JUnit test with #Parameterized runner allows you to run multiple iterations of the same test with different inputs.
You can read the test parameters from whatever source you wish and use them in the parameterized test without the need to copy the test method for every input.
You'll need at least JUnit 4.11 to use Parameterized.

JUnit Test Cases not changing even though files change

I use Eclipse and Maven and have made a single JUnit test, just to test if it works. The first time I ran the test everything went as expected, but since then, every time I run it, I get the same result, even though I'm changing the actual test-file's content.
I tried just emptying the file, then it said that there are no JUnit test files. But as long as I just have #Test in front of a method in that file, I always get the same results.
Anyone know why that could be?
I tried restarting eclipse.
EDIT:
Just realized that I'm not getting the test results since there is an exception before it gets tested. So, the problem is that I'm always getting the exception even though I changed the file.
Testclass:
public class zipTester {
/**
* The class to be tested on.
*/
private Generator generator;
/**
* Sets up the generator.
*/
#Before
public void setUp() {
generator = new Generator(null, 0);
}
/**
* Creates a zip file and tests whether it exists.
*/
#Test
public void testCreateZip() {
File file = new File("/Users/nicola/Documents/trunk);
generator.createZip(file, new Vector<File>());
}
}
Changed TestClass:
public class zipTester {
#Test
public void heyo() {
}
}
Always getting the following Exception:
java.io.FileNotFoundException: /Users/nicola/Documents/trunk (No such file or directory)
...
1 May be you should clean your project
2 and then recheck project-BuildAutomatically
if still have something wrong,
you can right-click your project "java build path" and open the first tab Source
set default output folder content "test/target/classes"
good luck :)
i think your code was not compiled by eclipse
Seems that happen when there is no file in the relevant location.Because you are passing the file to Generator and try to access that file.Then this exception happen as there are no file to access with generator.
You can follow the below steps to avoid this scenario.
First check is that file exist in that location as below,
File file = new File("/Users/nicola/Documents/trunk");
assertTrue(file.exists());
Then check with your Generator.

TestNG test passes on Linux, fails on windows

For some reason the test below fails on Windows, but passes on Linux. The test is designed to generate an exception in the code being tested. The exception is basically a file exception. The approach is to make the file unreadable in order to generate the exception. It looks like the setReadable(false) has no affect on Windows.
#Test(dependsOnGroups = "expectedFlow",expectedExceptions = ParserException.class)
#Parameters("unreadableFile")
public void mineDataParserExceptionTest(String unreadableFile) throws ParserException{
AbstractParser parser;
File f = new File(unreadableFile);
f.setReadable(false);
parser = ParserFactory.getParser(ParserFactory.TYPES.SAR);
parser.mine(fileHelper, xml);
}
You should check the return value to see if it succeeded; however, it seems likely that f.setReadable(false, false); might be a better idea, since otherwise it is only supposed to alter the read permission for the owner of the file.

Static initialization of properties files fails with ant build

I have a small java project which I execute using TestNG + Eclipse, and it works well.
I have externalized test data using properties file and I initialize it in one static block of my test class -
public class SanityTest extends SelTestCase {
static Properties properties = new Properties();
static String pickUp;
static String dropOff;
static {
try {
properties
.load(SanityTest.class
.getResourceAsStream("/com/product/testdata/testdata.properties"));
pickUp = properties.getProperty("pickUp");
dropOff = properties.getProperty("dropOff");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Verifies the booking of car on car hire market
* #throws Exception
*/
#Test
public void testBookingModule() throws Exception {
// Some tests here
}
But when I execute same using ant build (1.8) I encounter following exception on target "run" -
[testng] Caused by: java.lang.NullPointerException
[testng] at java.util.Properties$LineReader.readLine(Properties.java:418)
[testng] at java.util.Properties.load0(Properties.java:337)
[testng] at java.util.Properties.load(Properties.java:325)
I could not figure out much and also checked that "bin" is created and has all respective files.
Is there any thing I missed?
It seems strange to me that you have to use the package/directory name to retrieve your file loaded as a resource by the class loader.
Usually when you use getResourceAsStream, you put your data file where your class is, where the .class file is (or in the resource directory and eclipse will copy it at build time), and the you load it by specifying only the name of the file.
Try
properties.load(SanityTest.class.getResourceAsStream("testdata.properties"));
where testdata.properties is in the same folder as SanityTest.class
Regards,
stéphane
It seems like you get the stream from the property file.
Could this exception come from badly formatted prop file, which leads to null being returned somewhere?

Unit test with files system dependency - hidden files

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?
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
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.
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.
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...

Categories

Resources