JUnit : When do I declare a TemporaryFolder object? - java

I am trying to test a method that copies a source file to a dest file using JUnit's TemporaryFolder. I get a Java IOException when I try run this test however. Does it matter where I make the declaration for the folder? (My test class has several different tests in it). And if so, what is the proper way to do it? I ask because I currently have several unit tests above this code, then I try to set up the testing for the file copying. Maybe the #Rule-#Before-#Test block needs to be in its own class? Here is the snippet where I have coded the test:
...other tests...then:
#Rule
public static TemporaryFolder tmp = new TemporaryFolder();
private File f1, f2;
#Before
public void createTestData() throws IOException {
f1 = tmp.newFile("src.txt");
f2 = tmp.newFile("dest.txt");
BufferedWriter out = new BufferedWriter(new FileWriter(f1));
out.write("This should generate some \n" +
"test data that will be used in \n" +
"the following method.");
out.close();
}
#Test
public void copyFileTest() {
out.println("file 1 length: " + f1.length());
try {
copyFile(f1, f2);
} catch (IOException e) {
e.getMessage();
e.printStackTrace();
}
if (f1.length() != f2.length())
fail();
else if (!f1.equals(f2))
fail();
assertSame(f1, f2);
}
When I run this test class, all 11 of my tests now fail (which previously passed) and I get java.io.IOException: No such file or directory.

So looking at the JUnit Javadoc, I have found out that any declaration under #Rule must be public, and not static. So I took out the static and just have:
#Rule
public TemporaryFolder tmp = new TemporaryFolder();
I still do not know for sure if it matters where this declaration is made when you have other unit tests in your class that do not use the #Rule declaration, but this did allow me to run through my tests successfully.

If you really want to declare TemporaryFolder as static, you can use #ClassRule which is used to annotate static fields that contains Rule.
#ClassRule
public static TemporaryFolder tmp = new TemporaryFolder();
Reference: http://junit-team.github.io/junit/javadoc/4.10/org/junit/ClassRule.html

Related

JUnit testing deletion of a text file using a testing text file

I am trying to write a JUnit test for a java code that with three methods.
FileDeletion.java:
public static void fileDeletion(String filePath) {
File file = new File(filePath);
file.delete();
}
I looked online on how to test this, but it came up with how to make a temporary file in JUnit which is "guaranteed to be deleted after the test finishes".
See: https://howtodoinjava.com/junit/junit-creating-temporary-filefolder-using-temporaryfolder-rule/
How do I make a file which can be created and then subsequently deleted in a JUnit Test?
Any help would go a long way, many thanks.
I would consider using JUnit's TemporaryFolder rule to help you set up the file and directory structure you need for your test which is cleaned up after your test.
public class DeleteFileTest {
#Rule
public TemporaryFolder folder = new TemporaryFolder();
#Test
public void test() {
final File file = folder.newFile("myfile1.txt");
file.delete();
//Assert
}
}

TemporaryFolder not being deleted using JUnit #Rule

I'm using a temporary folder in my unit test using the #Rule of JUnit.
The folder is not being deleted after the tests finish
Java version : 1.8
JUnit version: 4.12
Os windows 10
I'm creating a file.csv under a temp folder in order to edit it using CSVPrinter from org.apache.commons
public class MyService {
public void createCSVFile(String basePath) {
try (FileWriter out = new FileWriter(format("%s/file.csv", basePath));
CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT.withHeader(HEADERS))) {
//printer.PrintRecord(args);
} catch (IOException e) {
log.error("Failed to create file.csv under " + basePath, e);
}
}
}
The test:
#Rule
public TemporaryFolder folder = new TemporaryFolder();
private String folderPath;
private MyService myService;
#Before
public void setup() throws IOException {
folder.newFile("file.csv");
folderPath = folder.getRoot().getPath();
}
#Test
public void testing_myService() {
myService.createCSVFile(folderPath);
//Assert
}
When i open the folder ex: C:\Users\me\AppData\Local\Temp\junit2290989758736528709
I can still see the file.csv as it was not deleted
I tried to migrate the create of the file to become in the tests. It did not fix it
#Test
public void testing_myService() {
folder.newFile("file.csv");
myService.createCSVFile(folder.getRoot().getPath());
//Assert
}
I added an #After method to delete the folder
#After
public void cleanup() throws IOException {
//Tried several ways to delete the folder and file as well
//FileUtils.forceDelete(folder.getRoot().getAbsoluteFile());
//folder.getRoot().delete();
//FileUtils.deleteDirectory(folder.getRoot());
//new File(folderPath +"/file.csv").delete();
//All methods did not delete neither the direcotry (with exception can't delete file.csv) nor deleted the file.csv
}
I also tried to call the folder.create(); and folder.delete(); myself without using the #Rule
But the folder wasn't deleted as well
The file.csv and folder are marked as read-only when viewing the properties on windows
I tried to change that in the code
folder.setWritable(true);
folder.setReadable(true);
folder.setExecutable(true);
Didn't manage to delete the folder as well
My aim is to find a solution that works for any environment where the code is checked out ex: CI pipeline on a linux server and on windows
any other reason for this behavior?
I suspect that some code is holding a file handle, preventing the temporary directory from being deleted.
I suggest:
#Rule
public final TemporaryFolder folder = TemporaryFolder.builder()
.assureDeletion()
.build();
That should cause TemporaryFolder to throw an exception if it could not delete the folder.
You should probably be creating and deleting in a folder within your project structure.
But it's probably not working because of a permission issue:
Either change the permissions of the folder so that the program has priveledges to delete, or run the program/IDE as an administrator.
That should fix the problem.

Deleting File and Directory in JUnit

I'm writing a test for a method that creates a file in a directory. Here's what my JUnit test looks like:
#Before
public void setUp(){
objectUnderTest = new ClassUnderTest();
//assign another directory path for testing using powermock
WhiteBox.setInternalState(objectUnderTest, "dirPathField", mockDirPathObject);
nameOfFile = "name.txt";
textToWrite = "some text";
}
#Test
public void shouldCreateAFile(){
//create file and write test
objectUnderTest.createFile(nameOfFile, textToWrite);
/* this method creates the file in mockPathObject and performs
FileWriter.write(text);
FileWriter.close();
*/
File expect = new File(mockPathObject + "\\" + nameOfFile);
assertTrue(expect.exist());
//assert if text is in the file -> it will not be called if first assert fails
}
#After
public void tearDown(){
File destroyFile = new File(mockPathObject + "\\" + nameOfFile);
File destroyDir = new File(mockPathObject);
//here's my problem
destroyFile.delete(); //why is this returning false?
destroyDir.delete(); //will also return false since file was not deleted above
}
I was able to delete the File using deleteOnExit() but I will not be able to delete the directory using delete or deleteOnExit. I will also perform other test for other scenarios in this test script so I don't want to use deleteOnExit.
I don't know why I cannot delete it in JUnit test script while I can delete a file created and modified by FileWriter in runtime when the code is not a JUnit test. I also tried performing an infiniteLoop after the test method and delete the file manually but it tells me that other program is still using the file though I'm able to modify its content.
Hope somebody can suggest a way to delete the files and directories created during the tests. Thanks :D
For more clarity, the method I test looks like this Unit testing method that invokes FileWriter
Edit:Here is the method to test
public void createFile(String fileName, String text){
//SOME_PATH is a static string which is a field of the class
File dir = new File(SOME_PATH); //I modified SOME_PATH using whitebox for testing
if(!dir.exists()){
booelan createDir = dir.mkdirs();
if(!createDir){
sysout("cannot make dir");
return;
}
}
try{
FileWriter fileWrite = new FileWriter(dir.getAbsolutePath() + "/" + fileName, true);
fileWrite.write(text);
fileWrite.close();
}
catch(Exception e){
e.printStackTrace();
}
}
I cannot modify this method as other developers created it. I was just instructed to create unit tests for test automation. Thanks.
Use the #Rule annotation and the TemporaryFolder classfor the folder that you need to delete.
http://kentbeck.github.com/junit/javadoc/4.10/org/junit/Rule.html (404 not found)
Update example of usage by http://junit.org/junit4/javadoc/4.12/org/junit/rules/TemporaryFolder.html:
public static class HasTempFolder {
#Rule
public TemporaryFolder folder= new TemporaryFolder();
#Test
public void testUsingTempFolder() throws IOException {
File createdFile= folder.newFile("myfile.txt");
File createdFolder= folder.newFolder("subfolder");
// ...
}
}
This is how I usually clean up files:
#AfterClass
public static void clean() {
File dir = new File(DIR_PATH);
for (File file:dir.listFiles()) {
file.delete();
}
dir.delete();
}
Your directory must be empty in order to delete it, make sure no other test methods are creating more files there.
Ensure you are closing the FileWriter instance in a finally block.
Ensure that the method objectUnderTest.createFile(nameOfFile, textToWrite) actually closes any opened streams?
I think the best approche is te delete after JVM exit :
Path tmp = Files.createTempDirectory(null);
tmp.toFile().deleteOnExit();

JUnit Rule TemporaryFolder

I'm creating a TemporaryFolder using the #Rule annotation in JUnit 4.7. I've tried to create a new folder that is a child of the temp folder using tempFolder.newFolder("someFolder") in the #Before (setup) method of my test. It seems as though the temporary folder gets initialized after the setup method runs, meaning I can't use the temporary folder in the setup method. Is this correct (and predictable) behavior?
This is a problem in Junit 4.7. If you upgrade a newer Junit (for example 4.8.1) all #Rule will have been run when you enter the #Before method:s. A related bug report is this: https://github.com/junit-team/junit4/issues/79
This works as well. EDIT if in the #Before method it looks like myfolder.create() needs called. And this is probably bad practice since the javadoc says not to call TemporaryFolder.create(). 2nd Edit Looks like you have to call the method to create the temp directories if you don't want them in the #Test methods. Also make sure you close any files you open in the temp directory or they won't be automatically deleted.
<imports excluded>
public class MyTest {
#Rule
public TemporaryFolder myfolder = new TemporaryFolder();
private File otherFolder;
private File normalFolder;
private File file;
public void createDirs() throws Exception {
File tempFolder = myfolder.newFolder("folder");
File normalFolder = new File(tempFolder, "normal");
normalFolder.mkdir();
File file = new File(normalFolder, "file.txt");
PrintWriter out = new PrintWriter(file);
out.println("hello world");
out.flush();
out.close();
}
#Test
public void testSomething() {
createDirs();
....
}
}

Run all tests in a source tree, not a package

My unit tests are in a separate directory tree from my integration tests, but with the same package structure. My integration tests need external resources (e.g. a server) to be available, but my unit tests are properly independent of each other and the environment.
In IntelliJ-IDEA (v7) I have defined a JUnit Run/Debug Configuration to run all the tests in the top-level package, and this of course picks up my integration tests which fail.
I want to define a run-junit configuration that runs all my unit tests. Any ideas?
The answer is to create a test suite that contains only those tests underneath the unit test folder and run that instead. There is a junit-addon which does just this called DirectorySuiteBuilder but I only found this after I had pretty much re-invented the wheel.
And it's already been asked here!
import junit.framework.JUnit4TestAdapter;
import junit.framework.TestSuite;
import java.io.File;
import java.io.IOException;
public class DirectoryTestSuite {
static final String rootPath = "proj\\src\\test\\java\\";
static final ClassLoader classLoader = DirectoryTestSuite.class.getClassLoader();
public static TestSuite suite() throws IOException, ClassNotFoundException {
final TestSuite testSuite = new TestSuite();
findTests(testSuite, new File(rootPath));
return testSuite;
}
private static void findTests(final TestSuite testSuite, final File folder) throws IOException, ClassNotFoundException {
for (final String fileName : folder.list()) {
final File file = new File( folder.getPath() + "/" +fileName);
if (file.isDirectory()) {
findTests(testSuite, file);
} else if (isTest(file)) {
addTest(testSuite, file);
}
}
}
private static boolean isTest(final File f) {
return f.isFile() && f.getName().endsWith("Test.java");
}
private static void addTest(final TestSuite testSuite, final File f) throws ClassNotFoundException {
final String className = makeClassName(f);
final Class testClass = makeClass(className);
testSuite.addTest(new JUnit4TestAdapter(testClass));
}
private static Class makeClass(final String className) throws ClassNotFoundException {
return (classLoader.loadClass(className));
}
private static String makeClassName(final File f) {
return f.getPath().replace(rootPath, "").replace("\\", ".").replace(".java", "");
}
}
IntelliJ IDEA CE 10.5 has a (new?) option to run all tests inside a configured directory:
Unfortunately there's no way to separate the output from the IntelliJ compile other than by classes and test classes within a single module (it's the classes that test runner is looking at).
So when I have integration tests I simply use a second module specific to these tests to get round this problem, specifying output directories as necessary for each module.

Categories

Resources