I wrote a unit test with junit 5 that tests some file system logic for which I need a folder and some files. I found the TempDir annotation in the documentation and used that to create a folder, into which I saved some files. Something like:
#TempDir
static Path tempDir;
static Path tempFile;
// ...
#BeforeAll
public static void init() throws IOException {
tempFile = Path.of(tempDir.toFile().getAbsolutePath(), "test.txt");
if (!tempFile.toFile().createNewFile()) {
throw new IllegalStateException("Could not create file " + tempFile.toFile().getAbsolutePath());
}
// ...
}
In junit4 it was possible to use TemporaryFolder#newFile(String). This doesn't seem to be around in junit5.
Am I missing something? It works so I suppose that's fine but I was wondering if there is a cleaner way to create a new file directly with the junit 5 api.
You can simplify the amount of typing for getting temp files if you make use of the built in methods of Files. This is a more concise definition to provide tempFile which should give similar error handling:
#TempDir
static Path tempDir;
static Path tempFile;
#BeforeAll
public static void init() throws IOException {
tempFile = Files.createFile(tempDir.resolve("test.txt"));
}
Ensure that you have a recent version of JUNIT5. The test below should pass, but fails in some older versions of JUNIT which do not generate unique values of #TempDir for fields tempDir and mydir:
#Test void helloworld(#TempDir Path mydir) {
System.out.println("helloworld() tempDir="+tempDir+" mydir="+mydir);
assertFalse(Objects.equals(tempDir, mydir));
}
As shown here (https://www.baeldung.com/junit-5-temporary-directory) you can either annotate a File or a Path with #TempDir, and write to the designated File using java.nio.Files#write with a Path for its target argument.
Related
Let's say I have a method like:
public void copyAndMoveFiles() throws IOException {
Path source = Paths.get(path1);
Path target = Paths.get(path2);
if (Files.notExists(target) && target != null) {
Files.createDirectories(Paths.get(target.toString()));
}
for (String fileInDirectory: Files.readAllLines(source.resolve(fileToRead))) {
Files.copy(source.resolve(fileInDirectory), target.resolve(fileInDirectory), StandardCopyOption.REPLACE_EXISTING);
}
}
How would I do a unit test on this? I have tried looking at mockito but it doesn't return anything or have anything I can assert. I read about JimFs, but for some reason, I can't grasp my head around that.
I don't think mocking is the right way to go here. Since you're code reads and writes files, you need a file system, and you need to assert its state at the end of the test.
I'd create temporary directories for source and target (e.g., using JUnit's TempDir). Then, you can set up various test cases in the source directory (e.g., it's empty, one file, nested directories, etc) and at the end of the test used java.io functionality to assert the files were copied correctly.
EDIT:
stub-by example of the concept:
class MyFileUtilsTest {
#TempDir
File src;
#TempDir
File dest;
MyFileUtils utils;
#BeforeEach
void setUp() {
utils = new MyFileUtils();
}
#Test
void copyAndMoveFiles() throws IOException {
// Create a file under src, initialize the utils with src and dest
File srcFile = File.createTempFile("myprefix", "mysuffix", src);
utils.copyAndMoveFiles();
File destFile = new File(dest, srcFile.getName());
assertTrue(destFile.exists());
}
}
public class ConnectionPointTest {
#Test
public void testMockito() throws IOException {
DataInputStream dataInputStream = mock(DataInputStream.class);
when(dataInputStream.readUTF()).thenReturn("Test");
new JustTest(dataInputStream).doTest();
}
public class JustTest {
DataInputStream dataInputStream;
public JustTest(DataInputStream dataInputStream) {
this.dataInputStream = dataInputStream;
}
public void doTest() throws IOException {
String s = dataInputStream.readUTF();
System.out.println(s);
}
}
}
I implement JUnit testing + Mockito in the project. Then I try to mock my DataInpuStream, I have an exeption at this code :
when(dataInputStream.readUTF()).thenReturn("Test");
P.S. class JustTest is only for show you what I want to mock.
There is exeption:
java.lang.NullPointerException
at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:337)
at java.io.DataInputStream.readUTF(DataInputStream.java:589)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
...
You are trying to mock a final method:
public final String readUTF() throws IOException {
return readUTF(this);
}
Mockito (v2.x) supports this but it requires additional configuration. More details in the docs:
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
So, create a file named org.mockito.plugins.MockMaker with this content:
mock-maker-inline
Place this file in a folder named mockito-extensions on your test classpath (if you are using Maven just create this folder in src/test/resources)
Re run your test.
With this configuration in place I have successful run your test with:
JUnit 4.12
Mockito 2.7.19
I am currently working on a method that will create files and directories. Bellow is the use case & problem explained.
1) When a user specifies a path e.g "/parent/sub folder/file.txt", the system should be able to create the directory along with the file.txt. (This one works)
2) When a user specifies a path e.g "/parent/sub-folder/" or "/parent/sub-folder", the system should be able to create all directories. (Does not work), Instead of it creating the "/sub-folder/" or /sub-folder" as a folder, it will create a file named "sub-folder".
Here is the code I have
Path path = Paths.get(rootDir+"test/hello/");
try {
Files.createDirectories(path.getParent());
if (!Files.isDirectory(path)) {
Files.createFile(path);
} else {
Files.createDirectory(path);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
You need to use createDirectories(Path) instead of createDirectory(path). As explained in the tutorial:
To create a directory several levels deep when one or more of the
parent directories might not yet exist, you can use the convenience
method, createDirectories(Path, FileAttribute). As with the
createDirectory(Path, FileAttribute) method, you can specify an
optional set of initial file attributes. The following code snippet
uses default attributes:
Files.createDirectories(Paths.get("foo/bar/test"));
The directories
are created, as needed, from the top down. In the foo/bar/test
example, if the foo directory does not exist, it is created. Next, the
bar directory is created, if needed, and, finally, the test directory
is created.
It is possible for this method to fail after creating some, but not
all, of the parent directories.
Not sure of which File API you are using. But find below the simplest code to create file along with folders using java.io package.
import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) {
FileTest fileTest = new FileTest();
fileTest.createFile("C:"+File.separator+"folder"+File.separator+"file.txt");
}
public void createFile(String rootDir) {
String filePath = rootDir;
try {
if(rootDir.contains(File.separator)){
filePath = rootDir.substring(0, rootDir.lastIndexOf(File.separator));
}
File file = new File(filePath);
if(!file.exists()) {
System.out.println(file.mkdirs());
file = new File(rootDir);
System.out.println(file.createNewFile());
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
In the unit tests as a side effect I am creating screenshots for various parts of the GUI.
I want to use these screenshots when compiling the documentation.
Therefore I want to save them to a directory within the source tree.
Is there any reliable way to get the source directory root when running a junit test?
If not, how can I make sure that unit tests run with cwd=project root when using eclipse, and when using maven?
wether you execute tests on eclipse or using maven, if you don't specify a path when you create the file it's automatically created at project root directory.
so if you specify a relative folder your files will go there :
public class TestFileCreation {
#Test
public void testFileCreation() throws IOException {
File f = new File("src/main/resources/hello.txt");
OutputStream ostream = new FileOutputStream(f);
String data = "Hello there !";
ostream.write(data.getBytes());
ostream.close();
}
}
will create a file inside the $PROJECT/src/main/resources.
Hope my answer helps
You can base on your classes location. Proposed solution here is to use class that will surely be in classpath. Then you can use class.getResource(""). Example
public class ResouceRoot {
public static String get() {
String s = ResouceRoot.class.getResource("").toString();
if (s.startsWith("jar:")) {
s = s.replace("jar:", "").replaceAll("!.*", "");
} else {
s = s.replaceAll("classes.*", "classes");
}
File f = new File(s.replace("file:", ""));
return f.getParentFile().getParentFile().getAbsolutePath();
}
public static void main(String[] args) throws IOException {
System.out.println(get());
}
}
(this code will give base dir for netbeans projects if they are launched from netbeans or by java -jar ... )
I have a function where I am trying to load a file to a URL object, because the example project said so.
public class SecureFTP {
public static void main(String[] args) throws IOException , ClassNotFoundException, SQLException , JSchException, SftpException{
File file = new File("/home/xxxxx/.ssh/authorized_keys");
URL keyFileURL = this.getClass().getClassLoader().getResource(file);
I tried using SecureFTP.class.getResource, but it still could not compile it.
I am fairly new to Java, so I know I am doing something wrong.
The main method is a static method, so trying to access this (= the current Object) will not work.
You can replace that line by
URL keyFileURL = SecureFTP.class.getClassLoader().getResource("/home/xxxxx/.ssh/authorized_keys");
From: How to call getClass() from a static method in Java?
Just use TheClassName.class instead of getClass().
Old question but this hasn't been said yet. You can do this from a static context:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
classLoader.getResource("filename");
It can't compile because getResource takes a resource name (a String, and not a File) as parameter, in order to load a resource using the class loading mechanism (from the classpath). Using it with a File makes no sense. If you want to open a file, just use a FileInputStream or a FileReader.
See http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource%28java.lang.String%29, and include the compiler error message next time you have such a question.
SecureFTP.class.getClassLoader().getResource(<<your resource name>>);
Should do the trick!
Do it this way so that it works EITHER from a static method or an instance method:
public static String loadTestFile(String fileName) {
File file = FileUtils.getFile("src", "test", "resources", fileName);
try {
return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("Error loading test file: " + fileName, e);
return StringUtils.EMPTY;
}
}