Junit to use correct resources - java

When writing unit tests for the application, usually I create copy of some configurations that are in original main/resources and modify them for test purpose, but i leave the names the same. However Junit sometimes takes the one in src and sometimes the one in the test/resources.
How do we manage which one it picks up without renaming files?
For example i have some "config.json" which is in both test and main's resources, how does junit choose which one to pick when running a test...

Ok, just a quick answer:
You cannot exclude resources from src/main/resources. They are always inside your class path and thus they are part of your program/library.
But you shouldn't have to do so.
Log4j2 for example allows to have a differently named configuration file in the class path (while running the tests). Just name it log4j2-test.xml and it will be loaded prior to a non-test file.
Spring behaves the same when annotating the test classes with #ContextConfiguration.

Related

Load different resources when testing in Python

First of all let me put you in context. My main background is Java and I'm working in Python since 2 months ago. I don't know if the approach it's wrong due to my Java background and in Python has a different solution or it's just a technical ignorance problem.
In Java often you have a packaging structure like:
project
|___src
|___main
| |___java/MyClass.java
| |___resources/properties.file
|
|___test
|___java/MyClassTest.java
|___resources/properties.file
Thus, when you execute this from tests (with Maven or IDE):
this.getClass().getResourceAsStream(resourcePath);
Either Maven or IDE loads the test path in the classpath, making test resources available rather than the ones within the main package.
Conversely, when previous line is executed as main, only the resources within the main path are loaded to the classpath.
My question is: Is there any mechanism in Python to simulate this feature? Does Python have other ways to manage resources depending on the execution path?
I think mock might be what you are looking for. It allows for 'mock'ing out external functions to limit the test to strictly the unit under test.
This could mean changing some of the philosophy around some of it. For example, if you want to test that a function is reading a file correctly the filename would get passed to the method as a parameter. In your unit test for the function, pass in a different filename from your test folder.
In another test mock out the open call to the os to check that the method responds as expected when the file is not there, or cannot be opened, or whatever other mis-behaviors you want to test for.
No, Python has no deployable like Java has (WAR, JAR, etc...). You will run your code directly from the source, so, just read the file.
In the Java context, you do not have the code when it is deployed. So every resource should be package inside a file (JAR or WAR).
If you want to find the file in the current folder, look this question.
I don't know very well Python but you are right to ask yourself the question
as separating test and application code makes part of good practice to have a robust/reliable application and tests.
The pytest (a known test framework for Python) documentation explains in its best practice guide the two ways (separating and not separating the test code from the application).
Here is the part referencing the isolated layout :
Choosing a test layout / import rules
pytest supports two common test layouts:
Tests outside application code
Putting tests into an extra directory outside your actual application
code might be useful if you have many functional tests or for other
reasons want to keep tests separate from actual application code
(often a good idea): setup.py
mypkg/
init.py
app.py
view.py
tests/
test_app.py
test_view.py
...
This way your tests can run easily against an installed version of
mypkg.
Note that using this scheme your test files must have unique names,
because pytest will import them as top-level modules since there are
no packages to derive a full package name from. In other words, the
test files in the example above will be imported as test_app and
test_view top-level modules by adding tests/ to sys.path.
If you need to have test modules with the same name, you might add
init.py files to your tests folder and subfolders, changing them to packages: setup.py
mypkg/
...
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py
Now pytest will load the modules as tests.foo.test_view and
tests.bar.test_view, allowing you to have modules with the same name.
But now this introduces a subtle problem: in order to load the test
modules from the tests directory, pytest prepends the root of the
repository to sys.path, which adds the side-effect that now mypkg is
also importable. This is problematic if you are using a tool like tox
to test your package in a virtual environment, because you want to
test the installed version of your package, not the local code from
the repository.
In this situation, it is strongly suggested to use a src layout where
application root package resides in a sub-directory of your root:
setup.py
src/
mypkg/
init.py
app.py
view.py
tests/
init.py
foo/
init.py
test_view.py
bar/
init.py
test_view.py This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this
excellent blog post by Ionel Cristian Mărieș.
https://docs.pytest.org/en/latest/goodpractices.html

Spring ResourceLoader doesn't find resources in JAR

I am looking to create a hierarchy based on the Spring configurations. The simplest form is several "core" libraries and several "custom" projects that are able to override the beans in the "core" libraries.
When running very simply unit tests via Maven the "core" configuration isn't able to found causing the test to fail.
final Resource[] resources = applicatonContext.getResources("classpath*:core-*spring.xml");
Returns nothing. It isn't able to find the expected core-one-spring.xml or core-two-spring.xml that are located in my custom projects core dependencies.
Isn't it default behavior of Spring to look into the JARs on the classpath as well? Or is there something special I have to do?
When I run in my IDE (IntelliJ) the tests pass perfectly because the entire project is loaded and they are just files that Spring can find.
UPDATE
Spring is able to find the files if I add them explicitly without wildcards.
#ContextConfiguration({"classpath:core-one-spring.xml", "classpath:core-two-spring.xml", "classpath:custom-spring.xml", "classpath:test-spring.xml"})
or
final Resource[] resources = custom.getResources("classpath:core-one-spring.xml");
From the manual
Please note that " classpath*:" when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like " classpath*:*.xml" will not retrieve files from the root of jar files but rather only from the root of expanded directories. This originates from a limitation in the JDK’s ClassLoader.getResources() method which only returns file system locations for a passed-in empty string (indicating potential roots to search).

How to make IntellijIDEA ignore work-in-progress class files?

When I'm working in IntellijIDEA how do I tell it to ignore a class file that may have problems and I want to leave dormant for a while?
It will throw errors when I compile whatever class I am working on until I fix the first "dormant" class.
I have tried adding my class to a bogus package but Intellij doesn't like that either because the path doesn't match.
Settings | Compiler | Excludes, add your WIP files there:
You could use Refactor -> Rename File..., and change the file extension.
That is set at the inspection level
Configure Current File Analysis CTRL + SHIFT + ALT + H
I have profiles with differing inspection levels setup loosely based on the phase of my project builds ... I'd suggest taking a look at Customizing Inspection Profiles.
To ignore specific files during compilation you can add files individually or recursively in via the project settings panel ...
Configure Compiler Analysis CTRL + ALT + S :: Compiler => Validation
A bit late, still
If all your files are in the same package, then right-click on the package in the Project tool window and pick "Mark directory as -> Excluded".
All the classes inside the package won't be compiled. You can cancel exclusion any time you want the same way.
Usually, only the classes that are used in the application are actually compiled.
In your case, I would guess that it's only broken unit tests that hinder the compilation (as opposed to any other Java classes in the /main folder).
The reason is this: When running all unit tests in a package or source folder, IntelliJ searches and includes all the files that appear like unit tests by default: those with Test or Suite in the class name, but also those annotated with #Test or #Suite.
So the easiest way to exclude your test is to create a third source folder, call it /ignore, and not mark it as a source folder in IntelliJ. You can then drop any file you don't want to include in your compilation there temporarily, and drag it back to its original folder when you want to continue working on it. Beware, though: You will get only limited tool support if you open and edit the file within an unmarked source folder, so it should really be used for "parking" only.
You could also change the file extension, as the other answer suggests, but then IntelliJ will also change its handling of the file in other respects, not just during compilation.
Also, if you're using JUnit 4, you can always annotate any single test method, or the entire test class, with #Ignore, and it will be skipped during the test run. This requires the class to be formally correct, though, i.e.: no compile time errors.
P.S: You need to actually move the test to a different folder, if you really want the package to change - not just edit the package declaration. Otherwise, a non-matching declaration will also be considered an error.

Getting the current working resource directory in java maven project

I am currently working on a JUnit test that checks functionality responsible for loading/saving a process configuration from/to some file. Given that a particular configuration file is present in resources, the functionality loads parameters from the file. Otherwise the functionality attempts to create new configuration file and persist a default configuration coded in the class. Right now I am using .class.getResource() method to check if configuration file exists, and to retrieve the necessary information. This approach is proven to be working fine from both maven's "test-class" and "class" directories. However, I am having problems while attempting to save default configuration when the file does not exist, namely the .class.getResource() method returns null, as the resource does not yet exist. This stops me from building the target resource directory (context-dependent) where the file should be saved.
Is there a way to code my functionality to evaluate whether particular object is being executed as a test or in production? More precisely, how can I build a relative path to my resource files to point to either production resources (../classes/...) or test resources (../test-classes/..) depending on the execution mode in which the project currently is?
My question is somewhat similar to the following How should I discover test-resource files in a Maven-managed Java project? but I think it is different enough to warrant new thread.
If I understand you right, essentially your issue is that you have a Maven project, which reads a particular file (normally, and during unit tests), that determines the application's behaviour. If that file doesn't exist, your application creates it.
The problem with ClassLoader.getSystemResource(...), is that it's not actually scanning a single directory. Instead it's looking at Java's classpath to determine the location of that particular resource. If there's multiple directories on the classpath, it'll have a number of areas that the file could potentially be located in.
In a sense then, .getSystemResource(...) is one way. You're able to look-up the location of a file, but not get the appropriate location to place it.
*So what about when you need to put the file in the correct location?*
You have two options essentially:
Hard-code the location of the file: Noone likes doing that.
The locations that are scanned on the classpath are passed into the classloader. You could use, for example, the first one and create the file there.
The second option isn't actually a bad one; have a look at this sample code.
final Enumeration<URL> urls = ClassLoader.getSystemClassLoader().getResources("");
if(! urls.hasMoreElements()) {
LOG.error("No entries exist on the class path!");
System.exit(1);
}
final File configFile = new File(urls.nextElement().getFile(), "config.xml");
configFile.createNewFile();
LOG.info("Create a new configuration file: " + configFile.getPath());
System.exit(0);
This resolved the configuration file to be within my target folder: ..\target\classes\config.xml
Up to you what you do; happy to provide more tips & advice if you feel more is required.
It sounds like you want to do the following:
When your code runs, it tries to load the configuration file. When the configuration file is not found you want to create the configuration file. The twist is that
if you are executing the code in "production mode" (I presume using something like the exec-maven-plugin or jetty-maven-plugin depending on the nature of your code) you want the configuration file to be placed in ${project.build.outputDirectory}
if you are executing the code in "test mode" (e.g. via surefire or failsafe) you want the configuration file to be placed in ${project.build.testOutputDirectory}
What I would do is use the ServiceLoader pattern.
You create a ConfigFileStore interface that is responsible for storing your configuration.
The ConfigFileStoreFactory enumerates all the services implementing that interface (using the ServiceLoader API by getting all the /META-INF/services/com.yourpackage.ConfigFileStore resources and extracting the class names from those. If there are no implementations registered then it will instantiate a default implementation that stores the file in the path based on getClass() (i.e. working backwards to get to the ${project.build.outputDirectory} note that it should handle the case where the classes get bundled up into a JAR, and I would presume in such a case the config file might get stored adjacent to the JAR)
Note: The default implementation will not be registered in /META-INF/services
Then in src/test/java you extend the default implementation and register that extended implementation in src/test/resources/META-INF/services/com.yourpackage.ConfigFileStore
Now when running code that has the test code on the classpath, the test version will be found, that will pick up the getClass() for a class from ${project.build.testOutputDirectory} because it is from the test classpath's /META-INF/services.
When running code that does not have the test code on the classpath, the default implementation will pick up the getClass() for a class from ${project.build.outputDirectory}
Should do what you want.

Setting the root for relative file paths in JUnit, AppEngine

I have some code that references a filename. On the server, this reference is relative to my war directory. When I'm running tests, though, the relative root doesn't seem to be set - only absolute paths, starting at the root of my local HD, actually find the files.
I'm testing in the context of an AppEngine LocalServiceTestHelper, which returns my war directory in its getAppDir method, but still the code can't understand the relative path.
How can I set the root for relative filenames in JUnit tests?
There are a number of options. In any case, I'd encapsulate the file access (or at least the file path resolution) in a separate class. That way, you could:
Mock that class in your tests to provide the correct file (path)
Pass an environment variable to your test class to resolve the correct file (path)
Provide a fallback implementation if the file is not found (as it is the case in your tests)
etc...
For my unit tests, I created a utility class called SupportFilePathResolver (see the code). It finds the file by looking in the classpath. This works nicely if the files you care about are in the classpath. If not in the classpath, then this won't help you.

Categories

Resources