I am writing some JUnit tests with JUnit 5. Before each test I need to load a test resource and initialize some other stuff with it. For that I wrote my init method annotated with #BeforeEach, because that progress is always the same except that the resource to load should be a different one for each test.
I first thought of removing the #BeforeEach annotation, add a parameter to the init method to specify which resource should be loaded and call the init method myself from within each test at the beginning.
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class MyTest {
private Object testResource;
private void init(String resourcePath) {
// actually load the resource and initialize some fields here
this.testResource = "Loaded resource from: " + resourcePath;
}
#Test
public void test0() {
init("TestResource0");
assertEquals("Loaded resource from: TestResource0", testResource);
}
#Test
public void test1() {
init("TestResource1");
assertEquals("Loaded resource from: TestResource1", testResource);
}
}
That way I feel like I am undermining the whole structure of the JUnit test flow and I fear, that that could cause some issues in the future when extending the tests, by e.g. some fancy meta test programming, where I'm gonna rely on JUnit to provide the correct information about the current state of the test.
So I decided to keep the parameter for the resource to load on the init method and keep the #BeforeEach annotation. That way I needed to include a ParameterResolver. My first thought about the implementation of resolveParameter(ParameterContext, ExtensionContext) was to first find out what test is about to be executed and return the corresponding resource to be loaded for that test.
static class MyParamResolver implements ParameterResolver {
#Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
String test = extensionContext.getRequiredTestMethod()
.getName();
switch (test) {
case "test0":
return "TestResource0";
case "test1":
return "TestResource1";
}
throw new ParameterResolutionException("Unknown test " + test);
}
#Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return true;
}
}
I don't like that solution, because I first dont have safety for the names to be correct ensured by the compiler and secondly the resources to be loaded are not obviously connected to the corresponding test at first sight. I then thought it would be nice to provide the resource path somehow to an annotation, that is directly attached to the test method. Something like that:
#Test("test0")
public void test0() {
assertEquals("Loaded resource from: TestResource0", testResource);
}
#Test("test1")
public void test1() {
assertEquals("Loaded resource from: TestResource1", testResource);
}
...
#Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return extensionContext.getRequiredTestMethod()
.getAnnotation(Test.class)
.value();
}
Unfortunately the #Test annotation doesn't define any parameters and after some research in the JUnit docs I couldn't find any other annotation fitting in here. The best thing I can think of now is to create my own annotation and putting it on each test method. But I also think that this is a common problem, which can be solved without reinventing the weel myself. I just couldn't find anything.
Is there a convenient way to solve this problem, that doesn't need to invent own annotations. In other words: Is there an easy way, that keeps up the code quality and readability to solve this problem by just using the framework API that is already there?
ParameterizedTest is useful when you have the same steps for a test, but want to execute it with different parameters. That doesn't seem to be the case. You can simply use the TestInfo parameter to the #BeforeEach method to handle your case.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
public class JUnitTest {
#Test public void test1() {
System.out.println("Test");
}
#BeforeEach public void f(TestInfo info) {
System.out.println(info.getDisplayName());
}
}
I guess, you're looking for "container templates". They are not part of Jupiter, yet. But already scheduled for 5.4: https://github.com/junit-team/junit5/issues/871
Related
I have a JUnit test class which runs 15 tests. 5 of the tests are optional in that I only wish to run them if a particular variable gets initialized by an argument. If the variable value is null I'd like to ignore these tests. Is this possible and if so, how?
You could use JUnit4's Assume feature ...
It's good to be able to run a test against the code as it is currently written, implicit assumptions and all, or to write a test that exposes a known bug. For these situations, JUnit now includes the ability to express "assumptions"
For example:
#Before
public void setUp() {
org.junit.Assume.assumeTrue(yourCondition());
// ...
}
If yourCondition() does not return true then the test for which #Before is running will not be executed.
Approach 1:
You can use JUnit-ext. It has RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
Approach 2
Another approach is to use Assume. You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization. For example:
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
}
Approach 3
I think an another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}
I have a test case which has an #Autowired field. I would like to have one method for setting up the test case, as it has many #Test-annotated methods that will rely on the same generated data, (for which I need the autowired class).
What's a good way to achieve this?
If I have the #BeforeClass, then I need to make the method static, which breaks the autowiring.
1st solution
Use TestNG instead.
#Before* annotations behave this way in TestNG.
No method annotated with #Before* has to be static.
#org.testng.annotations.BeforeClass
public void setUpOnce() {
//I'm not static!
}
2nd solution
And if you don't want to do that, you can use an execution listener from Spring (AbstractTestExecutionListener).
You will have to annotate your test class like this:
#TestExecutionListeners({CustomTestExecutionListener.class})
public class Test {
//Some methods with #Test annotation.
}
And then implement CustomTestExecutionListener with this method:
public void beforeTestClass(TestContext testContext) throws Exception {
//Your before goes here.
}
Self-contained in one file that would look like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"commonContext.xml" })
#TestExecutionListeners({SimpleTest.class})
public class SimpleTest extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) {
System.out.println("In beforeTestClass.");
}
#Test
public void test() {
System.out.println("In test.");
}
}
I came up with the solution of creating a separate initialization method (not setUp) annotated with #PostConstruct. This is not really an elegant solution, but it makes sure that the autowired/injected fields are properly initialized by Spring before using them, (which was the initial problem with the statically #BeforeClass annotated method).
I have a class, which I use as a basis for my unit tests. In this class I initialize the whole environment for my tests, setting up database mappings, enter a number of database records across multiple tables, etc. That class has a method with a #BeforeClass annotation which does the initialization. Next thing, I extend that class with specific classes in which I have #Test methods.
My question is, since the before class is exactly the same for all these test classes, how can I ensure that they are run only once for all the tests.
One simple solution is that I could keep all the tests in one class. However, the number of tests is huge, also they are categorised based on functional heads. So they are located in different classes. However since they need the exact same setup, they inherit the #BeforeClass. As a result the whole setup is done at least once per test class, taking much more time in total than I would prefer.
I could, though, put them all in various subpackages under one package, hence if there is a way, how I can run set up once for all the tests within that package, it would be great.
With JUnit4 test suite you can do something like this :
#RunWith(Suite.class)
#Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
#BeforeClass
public static void setUp()
{
System.out.println("Runs before all tests in the annotation above.");
}
#AfterClass
public static void tearDown()
{
System.out.println("Runs after all tests in the annotation above.");
}
}
Then you run this class as you would run a normal test class and it will run all of your tests.
JUnit doesn't support this, you will have to use the standard Java work-arounds for singletons: Move the common setup code into a static code block and then call an empty method in this class:
static {
...init code here...
}
public static void init() {} // Empty method to trigger the execution of the block above
Make sure that all tests call init(), for example my putting it into a #BeforeClass method. Or put the static code block into a shared base class.
Alternatively, use a global variable:
private static boolean initialize = true;
public static void init() {
if(!initialize) return;
initialize = false;
...init code here...
}
Create one base class for all tests:
public class BaseTest {
static{
/*** init code here ***/
}
}
and every test should inherit from it:
public class SomeTest extends BaseTest {
}
You can make one BaseTest class with a #BeforeClass method, then have all the other tests inherit from it. This way, when each test object is constructed, #BeforeClass gets executed.
Also avoid executing it just once for all the test suite, since all the test cases should be independent. #BeforeClass should execute only once each test case, not test suite.
If you can tolerate adding spring-test to your project, or you are using it already, then a good approach is to use the technique described here: How to load DBUnit test data once per case with Spring Test
Not sure if anyone still is using JUnit and trying to fix it without using Spring Runner (aka no spring integration). TestNG has this feature. But here is a JUnit based solution.
Create a RunOnce per thread operation like so. This maintains a list of classes for which the operation has run.
public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();
public void run(Function f) {
if (t.get() == null) {
t.set(Arrays.asList(getClass()));
f.apply(0);
} else {
if (!((List) t.get()).contains(getClass())) {
((List) t.get()).add(getClass());
f.apply(0);
}
}
}
}
Back in your unit test
#Before
public beforeTest() {
operation.run(new Function<Integer, Void>() {
#Override
public Void apply(Integer t) {
checkBeanProperties();
return null;
}
});
}
private void checkBeanProperties() {
//I only want to check this once per class.
//Also my bean check needs instance of the class and can't be static.
}
My function interface is like this:
interface Function<I,O> {
O apply(I i);
}
When you use this way, you can perform operations once per class using ThreadLocal.
Is it possible to mock a class object using Mockito and/or PowerMockito?
Something like:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
An alternative to mocking Class might be to use a Factory instead. I know you are concerned about refactoring, but this could be done without changing the public API of the class. You haven't provided much code to understand the class you are trying to test, but here's an example of refactoring without changing the API. It's a trivial class, but it might give you an idea.
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
Of course, the easiest thing to do to test this trivial class would be to use a genuine Runnable class, but if you tried to mock the Class, you would run into the problems you're having. So, you could refactor it thus:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
Now Instantiator does exactly the (trivially simple) thing it was doing before with the same public API and no need for any client of the class to do any special injecting of their own. However, if you wanted to mock the factory class and inject it, that's very easy to do.
why not using an agent if you can't refactor the code there isn't many options, as #jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.
However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.
The main idea is to modify your java command and add :
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :
#Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG is also supported. Just check the wiki page for more information.
Hope that helps.
First, as stated in the comments, you would need to do:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
Then you would do this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
#Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
How about this. creating a get method of the has a Object (MS) in class PCService and then mock it.
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
#Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}
OK, so the #Ignore annotation is good for marking that a test case shouldn't be run.
However, sometimes I want to ignore a test based on runtime information. An example might be if I have a concurrency test that needs to be run on a machine with a certain number of cores. If this test were run on a uniprocessor machine, I don't think it would be correct to just pass the test (since it hasn't been run), and it certainly wouldn't be right to fail the test and break the build.
So I want to be able to ignore tests at runtime, as this seems like the right outcome (since the test framework will allow the build to pass but record that the tests weren't run). I'm fairly sure that the annotation won't give me this flexibility, and suspect that I'll need to manually create the test suite for the class in question. However, the documentation doesn't mention anything about this and looking through the API it's also not clear how this would be done programmatically (i.e. how do I programatically create an instance of Test or similar that is equivalent to that created by the #Ignore annotation?).
If anyone has done something similar in the past, or has a bright idea of how else I could go about this, I'd be happy to hear about it.
The JUnit way is to do this at run-time is org.junit.Assume.
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
// rest of setup.
}
You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization.
An assumption failure causes the test to be ignored.
Edit: To compare with the #RunIf annotation from junit-ext, their sample code would look like this:
#Test
public void calculateTotalSalary() {
assumeThat(Database.connect(), is(notNull()));
//test code below.
}
Not to mention that it is much easier to capture and use the connection from the Database.connect() method this way.
You should checkout Junit-ext project. They have RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
[Code sample taken from their tutorial]
In JUnit 4, another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}
Additionally to the answer of #tkruse and #Yishai:
I do this way to conditionally skip test methods especially for Parameterized tests, if a test method should only run for some test data records.
public class MyTest {
// get current test method
#Rule public TestName testName = new TestName();
#Before
public void setUp() {
org.junit.Assume.assumeTrue(new Function<String, Boolean>() {
#Override
public Boolean apply(String testMethod) {
if (testMethod.startsWith("testMyMethod")) {
return <some condition>;
}
return true;
}
}.apply(testName.getMethodName()));
... continue setup ...
}
}
A quick note: Assume.assumeTrue(condition) ignores rest of the steps but passes the test.
To fail the test, use org.junit.Assert.fail() inside the conditional statement. Works same like Assume.assumeTrue() but fails the test.