I have a junit test suite as below and it works as expected.
#RunWith(Suite.class)
#Suite.SuiteClasses({
abc.class,
xyz.class
})
public class RunSuiteIT {}
Now my requirement is to keep the class names (abc,xyz) in a json file and get it read during run time. Is it possible to do that in Java/JUnit?
Yes, you should be able to do this at runtime, which means you can't use an annotation. Instead you will need a static Suite suite() method that reads the JSON file and uses the reflection API to create the Class instances from the string input.
Related
I'm migrating unit tests from Junit4 to Junit5. In the test I'm using TemporaryFolder rule from Junit4 API. To keep the test working I added #EnableRuleMigrationSupport annotation:
#EnableRuleMigrationSupport
public final class SomeTest {
#Rule
public final TemporaryFolder tmp = new TemporaryFolder();
// tests ...
}
As I understand, in Junit5 I need to use extensions instead of rules, but I can't find any replacement for TemporaryFolder in Junit5 extensions. Does it exist? How to correctly replace TemporaryFolder rule with extension?
You can use the #TempDir annotation (JUnit 5.4+), described in §2.20.1 of the JUnit 5 User Guide. From the user guide (emphasis mine):
The built-in TempDirectory extension is used to create and clean up a temporary directory for an individual test or all tests in a test class. It is registered by default. To use it, annotate a non-private field of type java.nio.file.Path or java.io.File with #TempDir or add a parameter of type java.nio.file.Path or java.io.File annotated with #TempDir to a lifecycle method or test method.
Note: This extension was added in version 5.4 and is currently (as of 5.8.2) experimental.
Example of using an instance field:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Path; // or use java.io.File
class SomeTests {
#TempDir
Path directory; // may be private since 5.8
}
– Allow #TempDir fields to be private #2687
Example of using a parameter of a test method:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Path; // or use java.io.File
class SomeTests {
#Test
void testFoo(#TempDir Path directory) {
// do test...
}
}
Note: Constructor parameters are not supported.
When the directory is created and deleted is described in the Javadoc of #TempDir (documentation quote from JUnit 5.8.2):
Creation
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.
Scope
By default, a separate temporary directory is created for every declaration of the #TempDir annotation. If you want to share a temporary directory across all tests in a test class, you should declare the annotation on a static field or on a parameter of a #BeforeAll method.
Old behavior
You can revert to the old behavior of using a single temporary directory by setting the junit.jupiter.tempdir.scope configuration parameter to per_context. In that case, the scope of the temporary directory depends on where the first #TempDir annotation is encountered when executing a test class. The temporary directory will be shared by all tests in a class when the annotation is present on a static field or on a parameter of a #BeforeAll method. Otherwise — for example, when #TempDir is only used on instance fields or on parameters in test, #BeforeEach, or #AfterEach methods — each test will use its own temporary directory.
Deletion
When the end of the scope of a temporary directory is reached, i.e. when the test method or class has finished execution, JUnit will attempt to recursively delete all files and directories in the temporary directory and, finally, the temporary directory itself. In case deletion of a file or directory fails, an IOException will be thrown that will cause the test or test class to fail.
I often write tests of different types. Depending on test type it might have different setup.
For instance all my service tests have the following annotation under class declaration:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = NONE)
All controller tests have these annotations:
#RunWith(SpringRunner.class)
#WithMockUser
#WebMvcTest(controllers = MyController.class)
Another tests have different setup, etc.
Every time when I create a test I have to copy-paste this part from another test.
I'm looking for a solution that will help me automate this process in IntelliJ Idea.
Q: Is there any way to define JUnit Test Class templates which work differently depending on the type of the test?
Let's say class name ends with word "Service" - its generated test should use one template, if class name ends with "Controller" - its test should use another one, etc.
It is also possible to detect test type by package name or some other conditions like class content.
The JUnit code generation templates can be found under Settings > File And Code templates > Code.
You can't really create separate code templates, but what you could do is add logic to the existing templates. They use Velocity based directives.
So if, for example, we take the existing JUnit 4 template:
import static org.junit.Assert.*;
#parse("File Header.java")
public class ${NAME} {
${BODY}
}
We can modify it to the following:
import static org.junit.Assert.*;
#if($CLASS_NAME.contains("Service"))
//Import whatever you need for services here.
#end
#if($CLASS_NAME.contains("Controller"))
//Import whatever you need for controllers here.
#end
#parse("File Header.java")
#if($CLASS_NAME.contains("Controller"))
#set($CLASS_SUFFIX = ".class" )
#RunWith(SpringRunner.class)
#RunWithMock
#WebMvcTest(controllers = $CLASS_NAME$CLASS_SUFFIX)
#end
#if($CLASS_NAME.contains("Service"))
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = NONE)
#end
public class ${NAME} {
${BODY}
}
This way if you generate a new JUnit 4 test class through the context menu (hit alt-enter on the class name of the class you want to test and generate new test) it will generate different output if the name of the class to test contains 'Controller' or 'Service'. You might want to change that to endswith instead of contains depending on whatever naming conventions you use.
I've left out the actual import statements in both cases, but I'm sure you'll be able to add those.
My Test Automation Framework is KeywordDriven Framework. I want to add a test case which supports dataProvider class of TestNG. I can execute the Test case with DataProvider, separately. But, when I incorporate dataProvider test to Keyword framework, It stops its execution and showed the null parameter to that test.
Architecture of Framework is:
My TestSuite File consists all test cases in it.In which first-sheet of excel have all test cases with run mode and rest of the sheets have each test cases.
Second sheet of excel file is TestCase1:
Similarly, all test cases are documented in each sheet of excel file.In above screenshot, ‘keyword’ column against ‘object’. ‘Objects’ are object repository and all ‘Keywords’ are documented in Keyword file.
demo
Public class KeywordsApp extends DriverApp{
//Input data Keyword
public static String inputValues() throws Exception{
String message = "pass";
String data =testData.getCellData(currentTest, datacolumnname , testRepeat);
System.out.println("Enter :"+data);
driver.findElement(By.xpath(objects.getProperty(object))).clear();
driver.findElement(By.xpath(objects.getProperty(object))).sendKeys(data);
return "Pass";
}
//click button
public static String clickObject(){
driver.findElement(By.xpath(objects.getProperty(object))).click();
return "Pass";
}
}
In Keyword file, we documented all actions/methods and invoke these methods on mentioned objects.
In This framework, a DriverScript runs all these test cases mentioned in TestSuite excel file. Driver Script reads everything in excel file, load all related properties, excel and XML files, Initiate driver /browser for further execution.
Now, We have few test cases in which we have to perform repetitive actions, for example … we need to add multiple dependents to main profile I.e. 10 to 100 dependents.
We achieved this requirement by using dataProvider class in Testing, separately. But, We don't know, how to add this dataProvider class into Keywords file. So we can execute complete suite in one run.(As per TestSuite excel file).
Testsuite excel file path: https://drive.google.com/open?id=0B865ekOaGf3UeWk5dkpTLUJiVWc.
Is there any way, to integrate dataProvider in above mentioned Keyword framework?
When jUnit runs a test suite containing multiple "sub suites", is it possible to filter tests found in different suites as to make them run only once? I'm working on a project with many database integration tests so it's desirable run these only once as to make it quicker.
Consider this "main suite":
#RunWith(Suite.class)
#SuiteClasses
({
ModuleASuite.class,
ModuleBSuite.class,
// More suites...
})
public class MainSuite
{}
And these "sub suites":
#RunWith(Suite.class)
#SuiteClasses
({
TestA1.class,
TestA2.class,
//... More tests only related to ModuleA
SomeTestUsedByManyModules.class
})
public class ModuleASuite
{}
#RunWith(Suite.class)
#SuiteClasses
({
TestB1.class,
TestB2.class,
//... More tests only related to ModuleB
SomeTestUsedByManyModules.class
})
public class ModuleBSuite
{}
Currently when running MainSuite using jUnit 4.4 (using Eclipse or Ant) it runs SomeTestUsedByManyModules twice. How can I make it run only once? I thought of making my own Runner but maybe there's an easer solution for this?
I don't know how to do it with #RunWith(Suite), but what about a different approach? ClassPathSuite lets you provide test name patterns to avoid the need to list them all out manually.
SuiteClasses will work just fine with a list of classes like {Test1.class,Test2.class}, but when I try to generate a static list of classes, it says incompatible types: required java.lang.Class<?> but found java.lang.Class<?>[]
What am I missing?
#RunWith(Suite.class)
#Suite.SuiteClasses(TestSuite.classes)
public class TestSuite {
public static Class<?> [] classes;
static {
classes = new Class<?> [1];
classes[0] = MyTest.class;
}
}
That shouldn't really work. You are intended to put the array within the annotation as a constant. Even if you got past this problem, the compiler would reject it. What you need to do is this:
#RunWith(Suite.class)
#Suite.SuiteClasses({MyTest.class, MyOtherTest.class})
public static class TestSuite {
}
Note the squiggly brackets.
I'm sure what you are trying to get at is to be able to build the list of classes in the suite dynamically.
I submitted a request to them to allow that, but in the mean time the only way to do it is to subclass the Suite class like so:
public class DynamicSuite extends Suite {
public DynamicSuite(Class<?> setupClass) throws InitializationError {
super(setupClass, DynamicSuiteBuilder.suite());
}
}
#RunWith(DynamicSuite.class)
public class DynamicSuiteBuilder {
public static Class[] suite() {
//Generate class array here.
}
}
#SuiteClasses is a class annotation defined in JUnit 4.4 in org.junit.runners.Suite.SuiteClasses. It allows you to define a suite class as described in the previous question.
By the way, the API document of JUnit 4.4 has a major typo for the org.junit.runners.Suite class (Suite.html).
Using Suite as a runner allows you to manually build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x static Test suite() method. To use it, annotate a class with #RunWith(Suite.class) and #SuiteClasses(TestClass1.class, ...). When you run this class, it will run all the tests in all the suite classes.
#SuiteClasses(TestClass1.class, ...) should be changed to #Suite.SuiteClasses({TestClass1.class, ...}).
Someone provided wrong information on build test suite in JUnit 4.4. Do not follow this:
JUnit provides tools to define the suite to be run and to display its results. To run tests and see the results on the console, run:
org.junit.runner.TextListener.run(TestClass1.class, ...);