Why isn't JUnit TemporaryFolder deleted? - java

The documentation for JUnit's TemporaryFolder rule states that it creates files and folders that are
"guaranteed to be deleted when the test method finishes (whether it
passes or fails)"
However, asserting that the TemporaryFolder does not exist fails:
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class MyTest {
#Rule
public TemporaryFolder _tempFolder = new TemporaryFolder();
#After
public void after() {
assertFalse(_tempFolder.getRoot().exists()); //this assertion fails!
}
#Test
public void pass() throws IOException {
assertTrue(true);
}
I also see that the file indeed exists on the file system.
Why is this not getting deleted?

This is because JUnit calls after() before it removed the temp folder. You can try to check temp folder in an #AfterClass method and you will see it's removed. This test proves it
public class MyTest {
static TemporaryFolder _tempFolder2;
#Rule
public TemporaryFolder _tempFolder = new TemporaryFolder();
#After
public void after() {
_tempFolder2 = _tempFolder;
System.out.println(_tempFolder2.getRoot().exists());
}
#AfterClass
public static void afterClass() {
System.out.println(_tempFolder2.getRoot().exists());
}
#Test
public void pass() {
}
}
output
true
false

I stumbled upon this question facing the same issue and in my case the cause of the missing deletion was an improper use of the temporary folder.
The toString() method returns the internal folder name, so when trying to create a new file within it, JUnit creates a new folder within the project root.
Adding the getRoot() method solved the issue.
Here's the code I blame:
#Rule
public TemporaryFolder projectFolder = new TemporaryFolder();
//some lines later...
FileUtils.copyFile(deployFile, new File(projectFolder + "/deploy.xml"));
//how I fixed it
FileUtils.copyFile(deployFile, new File(projectFolder.getRoot() + "/deploy.xml"));

Related

Junit not launching test case when it is an anonymous class

I'm trying to use JUnit for my functional testing. Basically I'm doing this to have access to the JUnit reports. Unfortunately I am running into a problem when trying to launch JUnit from a main method.
Basically I am developing a functional testing tool where the user can provide a test filename as a parameter from the command line. I've simplified it a bit below:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase() {
#Override
public String getPath() {
return args[0];
}
};
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
The TestCase class then acts on the supplied parameter and provides output:
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestCase {
private static final Logger LOGGER = LoggerFactory.getLogger(TestCase.class);
public String getPath() {
return "etc/Default.flow";
}
#Test
public void testFunc() {
try {
LOGGER.info("Entered testFunc()");
Launcher launcher = new Launcher(getPath());
launcher.launch();
launcher.awaitCompletion();
Assert.assertTrue(launcher.getStatus());
LOGGER.info("Success");
} catch (AssertionError e) {
LOGGER.error("Assertion error", e);
}
}
So from the above, we see that the Launcher instance will be launched with a different filename depending on what was entered on the command line.
The problem is however that Junit is not running my anonymous class. Basically the main method exits without any of the assertions or logging taking place. The TestCase testFunc() method is therefore not called at all.
However, when I change the TestCase instance to not be anonymous, everthing works as expected and the testcase is successful:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase();
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
Why would JUnit launch the Test class only when it is not anonymous?
If you add listener junit.addListener(new TextListener(System.out)); before running test you will see something like:
There were 2 failures:
1) initializationError(junit.MainClass$1)
java.lang.Exception: The class junit.MainClass$1 is not public.
...
2) initializationError(junit.MainClass$1)
java.lang.Exception: Test class should have exactly one public constructor
at org.junit.runners.BlockJUnit4ClassRunner.validateOnlyOneConstructor(BlockJUnit4ClassRunner.java:158)
at org.junit.runners.BlockJUnit4ClassRunner.validateConstructor(BlockJUnit4ClassRunner.java:147)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:127)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
It means that JUnit is unable to execute test cases represented by anonymous classes.

"folder has not yet been created" error when using JUnit temporary folder in testclass

I get the error "the temporary folder has not yet been created", which comes from an IllegalStateException thrown by the TemporaryFolder.getRoot() method. It looks like it's not initialized, but my research showed me that this is usually the case when the temp folder is initialized in setUp()-method. But using it with #Rule like I did should work in my opinion. Any ideas?
The test class
public class FileReaderTest extends TestCase {
#Rule
public TemporaryFolder folder = new TemporaryFolder();
public FileReaderTest(String testName) {
super(testName);
}
#Override
protected void setUp() throws Exception {
super.setUp();
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testCSVWriterAndReader() throws Exception{
testWriterAndReader(new CSVFileWriter(), new CSVFileReader());
}
private void testWriterAndReader(FileWriteService writer, FileReader reader) throws Exception {
folder = new TemporaryFolder();
File tempFile = folder.newFile("test.csv");
DataSet initializedData = createMockData();
writer.writeDataSetToFile(initializedData, tempFile.getPath());
DataSet readData = reader.getDataFromFile(new FileInputStream(tempFile));
assertEquals(initializedData, readData);
}
}
You're using JUnit 3 tests which don't support Rules. You have to use a JUnit 4 test for this. Therefore
Remove extends TestCase from the class definition.
Remove the constructor, the setUp and the tearDown method.
Add the #Test annotation to all test methods (Public methods that start with test.)
should do the migration. Afterwards you have to delete the line
folder = new TemporaryFolder();
from testWriterAndReader.
For more details about the migration: Best way to automagically migrate tests from JUnit 3 to JUnit 4?

How to run PowerMock on dynamically created TestCase

I was trying to mock my test suites. My test framework creates test cases by scanning test files on disk. So each time the test cases are dynamically created.
I was trying to use PowerMock. Below is the thing I tried first.
public class GroupTestcase_T extends TestSuite {
static void run() {
scan();
junit.textui.TestRunner.run(g);
}
static void scan() {
// scan disk
for (MyTestCase t : tests) { addTest(t); }
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase extends TestCase {
public MyTestCase(TestInfo info) {...}
#Override
protected void setUp() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
when(ClassToStub.methodToStub())
.thenReturn(new FakeProxy());
}
#Test
public void test() throws Exception {
// Test!
}
}
Above code seems not working:
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
I traced the code and found that PowerMockRunner are not called at all.
Also I tried manually force Junit to run it with PowerMockRunner:
Result result = junit.run(new PowerMockRunner(MyTestCase.class));
PowerMockRunner has only one constructor that takes the test class as parameter. My test cases are different each time but all share the same class.
Any idea how to use PowerMock if TestCase are dynamically created?
I was using Junit 4 / PowerMock 1.5
You can generate your tests with the parameterized tests feature and apply the #PowerMockRule.
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
#RunWith(Parameterized.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase{
#Parameters
public static Collection<Object[]> scan() {
return Arrays.asList(new Object[][] {
{ new TestInfo() }, { new TestInfo() } });
}
#Rule
public PowerMockRule rule = new PowerMockRule();
public MyTestCase(TestInfo info) {
// ...
}
#Test
public void test() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
PowerMockito.when(ClassToStub.methodToStub()).thenReturn(new FakeProxy());
assertTrue(ClassToStub.methodToStub() instanceof FakeProxy);
}
}
Beware, in your example, you are mixing junit 3 (extends TestSuite, protected setUp) and junit 4 (#Test) test definitions.

Can Selenium take a screenshot on test failure with JUnit?

When my test case fails, especially on our build server, I want to take a picture / screenshot of the screen to help me debug what happened later on. I know how to take a screenshot, but I was hoping for a way in JUnit to call my takeScreenshot() method if a test fails, before the browser is closed.
No, I don't want to go edit our bazillions of tests to add a try/catch. I could maybe, just possibly be talked into an annotation, I suppose. All of my tests have a common parent class, but I can't think of anything I can do there to solve this.
Ideas?
A few quick searches led me to this:
http://blogs.steeplesoft.com/posts/2012/grabbing-screenshots-of-failed-selenium-tests.html
Basically, he recommends creating a JUnit4 Rule that wraps the test Statement in a try/catch block in which he calls:
imageFileOutputStream.write(
((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));
Does that work for your problem?
If you want to quickly add this behavior to ALL your tests in the run you can use the RunListener interface to listen for test failures.
public class ScreenshotListener extends RunListener {
private TakesScreenshot screenshotTaker;
#Override
public void testFailure(Failure failure) throws Exception {
File file = screenshotTaker.getScreenshotAs(OutputType.File);
// do something with your file
}
}
Add the listener to your test runner like this...
JUnitCore junit = new JUnitCore();
junit.addListener(new ScreenshotListener((TakesScreenShots) webDriver));
// then run your test...
Result result = junit.run(Request.classes(FullTestSuite.class));
If you want to take a screenshot on test failure, add this class
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
public class ScreenShotOnFailure implements MethodRule {
private WebDriver driver;
public ScreenShotOnFailure(WebDriver driver){
this.driver = driver;
}
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
statement.evaluate();
} catch (Throwable t) {
captureScreenShot(frameworkMethod.getName());
throw t;
}
}
public void captureScreenShot(String fileName) throws IOException {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
fileName += UUID.randomUUID().toString();
File targetFile = new File("./Screenshots/" + fileName + ".png");
FileUtils.copyFile(scrFile, targetFile);
}
};
}
}
And Before all tests, you should use this Rule:
#Rule
public ScreenShotOnFailure failure = new ScreenShotOnFailure(driver));
#Before
public void before() {
...
}

Setting Test Suite to Ignore

I have many Test Suites with each one contains many Test Classes. Here is how they look like:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses( {ATest.class, BTest.class})
public class MyFirstTestSuite {
#BeforeClass
public static void beforeClass() throws Exception {
// load resources
}
#AfterClass
public static void afterClass() throws Exception {
// release resources
}
}
Sometimes I want to disable a whole Test Suite completely. I don't want to set each test class as #Ignore, since every test suite loads and releases resources using #BeforeClass and #AfterClass and I want to skip this loading/releasing when the test suite is ignored.
So the question is: is there anything similar to #Ignore that I can use on a whole Test Suite?
You can annotate the TestSuite with #Ignore.
#RunWith(Suite.class)
#SuiteClasses({Test1.class})
#Ignore
public class MySuite {
public MySuite() {
System.out.println("Hello world");
}
#BeforeClass
public static void hello() {
System.out.println("beforeClass");
}
}
doesn't produce any output.
SlowTest is a class defined by user. It can be empty (without any functions or attributes). You can name it whatever you want:

Categories