There are some cases that the software shall behave differently according to some environmental conditions, for example whether a file exists at some place or not.
In my case, I'm developing a library, and it is configured according to a configuration file in classpath, (and falls back to default behavior if the config file does not exists).
How shall I unit test this class?
I need to write tests for evaluating the class in following cases:
the file does not exists on classpath
the file with content A exist on classpath
the file with content B exist on classpath
But I don't know how to configure environment to justify all of them. And execute the test one after each other.
By the way I'm using Java, and I have both JUnit and TestNG on the test classpath.
Edit:
One of the problems is that the config file resides in classpath, so if the normal ClassLoader finds and loads it, it returns the same content as long as the same class loader is used.
And I believe using a custom ClassLoader for testing is so complicated, that it needs tests to validate the tests!
You can use a temporary file created by your test to mock out the path in your class.
ConfigurationTest.java:
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeThat;
import java.nio.file.Files;
import org.junit.Test;
public class ConfigurationTest {
private Configuration config = new Configuration();
#Test
public void testWithConfigFile() throws Exception {
config.configFile = Files.createTempFile("config_",".ini");
config.configFile.toFile().deleteOnExit();
assertFalse(config.isInDefaultMode());
}
#Test
public void testWithoutConfigFile() throws Exception {
assumeThat(Files.exists(config.configFile), is(false));
assertTrue(config.isInDefaultMode());
}
}
Configuration.java:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Configuration {
Path configFile = Paths.get("config.ini");
public boolean isInDefaultMode() {
return !Files.exists(configFile);
}
}
Related
I want to copy some files into a temporary directory. But the File I annotate with #TempDir does not seem to get injected.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
public class MyTempFileTest {
#TempDir
public File tempFolder;
#Test
public void testTempFolder() {
Assertions.assertNotNull(tempFolder);
}
}
the result is org.opentest4j.AssertionFailedError: expected: not <null>
I would instead expect it to be a random temporary directory, as was the case with #Rule TemporaryFolder tmpSudokus = new TemporaryFolder() in Junit4.
And according to the docs I can annotate a Java.io.File.
If I try to pass the tempDir as a directory
#Test
public void testTempFolderParam(#TempDir File tempFolder) {
Assertions.assertNotNull(tempFolder);
}
I get org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.io.File tempFolder] in executable [public void my.package.MyTempFileTest.testTempFolderParam(java.io.File)].
The test is part of an android project, my dependencies are:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2'
}
According to documentation Junit5 Docs
The temporary directory is only created if a field in a test class or a parameter in a lifecycle method or test method is annotated with #TempDir. If the field type or parameter type is neither Path nor File or if the temporary directory cannot be created, an ExtensionConfigurationException or a ParameterResolutionException will be thrown as appropriate. In addition, a ParameterResolutionException will be thrown for a constructor parameter annotated with #TempDir.
As I see in your example, you did use java.io.File so I guess your problem is in the creation part of the temporary folder.
I copied your example and it did work, the tempDir was not null
Dependencies :
junit-jupiter:5.7.2
junit-jupiter-engine:5.7.2
junit-jupiter-params:5.7.2
I need to add a variable value to a class-level annotation "#PactFolder" in a JUnit test. I've been able to achieve the dynamic assignment for this annotation using simple reflection in the #BeforeClass method.
However, This JUnit contract test runs with another annotation (#RunWith(PactRunner.class)). Now, since the #PactFolder annotation's purpose is to pass an absolute path to the PactRunner class, and PactRunner reads the value of #PactFolder at the time of invocation, the reflected variable value is of no use.
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import au.com.dius.pact.provider.junit.PactRunner;
import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit.loader.PactFolder;
import au.com.dius.pact.provider.junit.loader.PactSource;
import au.com.dius.pact.provider.junit.target.HttpTarget;
import au.com.dius.pact.provider.junit.target.TestTarget;
#PactFolder("<Dynamic value>")
#RunWith(PactRunner.class)
#Provider("CvSaveDataServiceProvider")
public class ContractTest {
#BeforeClass
public static void setConditions() {
PactFolder pactFolder = ContractTest.class.getAnnotation(PactFolder.class);
AlterPactFolderAnnotation.setAbsolutePactDirectory(ContractTest.class, PactFolder.class, ContractDirectoryRelativeModulePath.HRIS.getRelativeModulePath(), pactFolder);
System.out.println(ContractTest.class.getAnnotation(PactFolder.class).value());
}
#TestTarget
public HttpTarget target = new HttpTarget(8080);
}
I need to access contracts from a locally cloned repository, kept in multiple directories, with final aim to add paths of all directories in a single config file and initialize all tests in different directories from a single point using "mvn test" command (a simple batch file)
Is there a possible solution or any workaround to do this ?
We run code which does the standard for creating a temp directory:
import java.nio.file.Files;
And then:
tmp = Files.createTempDirectory("ourprefix-");
This, effectively, creates the directories under /tmp/ so that we get things like /tmp/ourprefix-1234 or similar.
Unfortunately, this base directory /tmp/ seems to be fixed and since on our build server lots of things tend to put their temp stuff there and because the partition the /tmp/ is on is rather small, this is a problem.
Is there a way to configure this facility from the outside (i. e. without changing the code)? I would have guessed that /tmp/ is a default and can be overridden by setting a special environment variable or (more Javaish) passing a special property to the compiler (e. g. -Djava.tmp.root=/path/to/my/larger/partition/tmp).
I tried using java.io.tmpdir but setting this did not have any effect; it seems to be the default in case nothing is given to createTempDirectory() but in our case the code passes a prefix.
Any idea how to achieve what I want without changing the source code?
EDIT
After some investigation I found that this works just fine:
import java.nio.file.Path;
import java.nio.file.Files;
import java.io.IOException;
public class TestTempDir {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("java.io.tmpdir"));
Path path = Files.createTempDirectory("myprefix-");
System.out.println(path.toFile().getAbsolutePath());
}
}
Compile with javac TestTempDir.java, prepare with mkdir tmp and run with java -Djava.io.tmpdir=pwd/tmp TestTempDir this just works as expected:
/my/work/path/tmp
/my/work/path/tmp/myprefix-1525078348397347983
My issue rather seems to be one with Jenkins and its Maven plugin which does not pass the set properties along to the test cases :-/
if you pass the java.io.tmpdir property as a custom JVM property as you run the JVM, it should work.
Something like that :
java -Djava.io.tmpdir=myPath myClass
I tested and it works :
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class TestTempDir {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("java.io.tmpdir"));
Path dir = Files.createTempDirectory("helloDir");
System.out.println(dir.toString());
}
}
$ java -Djava.io.tmpdir=D:\temp TestTempDir
D:\temp
D:\temp\helloDir5660384505531934395
I have the package structure something like this
src
main
java
com
org
-- Loader.java
resources
schemas
-- a.schema
-- b. schema
Now I want to be able to access the list of schemas under the schema folder which could vary with time from the Loader class. I package it as a jar and in runtime access all the files under the schema folder. How can I do it?
Do this inside Loader.java:
InputStream in = Loader.class.getResourceAsStream("/data/schemas/a.schema");
The leading slash means from starting from the root of classpath (i.e. your JAR file).
Using java 8, you should get it easily. See below code:
import java.util.stream.*;
import java.nio.file.*;
import java.util.*;
import java.io.*;
public class HelloWorld{
public static void main(String []args) throws IOException {
try (Stream<Path> filePathStream = Files.walk(Paths.get("/data/schemas/"))) {
List<File> filesInFolder = filePathStream.filter(Files::isRegularFile)
.map(Path::toFile)
.collect(Collectors.toList());
System.out.println(filesInFolder);
}
}
}
here the try-with-resource constructs ensures that the stream is closed automatically after using.
The Files class introduced in Java 7 has methods for handling links and symlinks but only as optional operations.
Is there any way of determining at runtime if a file system supports these operations before actually invoking the respective methods or do I need to call them and then catch the exception?
Classes like FileSystem or FileStore do not seem to contain anything in that regard (or I overlooked it).
I don't see any general approach that will work without relying on an UnsupportedOperationException or some other exception.
You could use a heuristic that assumes that only subclasses of BasicFileAttributesView support symbolic linking.
Note: The approach below will not work because FileAttributeViews and file attributes are not the same concept:
I did not get isSymbolicLink as one of the supported attributes with the following code on OS X 10.8.4:
package com.mlbam.internal;
import java.nio.file.Files;
import java.nio.file.FileStore;
import java.nio.file.FileSystems;
import java.nio.file.Paths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MainClass {
private static final Logger LOG = LoggerFactory.getLogger(MainClass.class);
public static void main(String[] args) {
try {
System.out.println("FileStore.supportsFileAttributeView('isSymbolicLink'): "
+ Files.getFileStore(Paths.get("/")).supportsFileAttributeView("isSymbolicLink"));
// Got: FileStore.supportsFileAttributeView('isSymbolicLink'): false
System.out.println(FileSystems.getDefault().supportedFileAttributeViews());
// Got: [basic, owner, unix, posix]
} catch (Exception e) {}
}
}
Original Answer:
If you have an instance of FileStore, you can use FileStore.supportsFileAttributeView("isSymbolicLink")
Or, if you have an instance of FileSystem, you can check that resulting Set<String> from FileSystem.supportedFileAttributeViews() contains the String "isSymbolicLink".
You can get the FileStore associated with a Path using Files.getFileStore(Path)
One way of getting the FileSystem is via FileSystems.getDefault()