Get string from #Test annotation TestNG - java

I am trying to get a string from a TestNG annotation #Test(groups="Foo") and then use this as a name for a folder I am dynamically generating.
How do I get the text "Foo" from the TestNG annotation so I can use it?

I think a simpler solution to reading the attribute of the annotation (which would involve reflection and friends) would be to use the same constant String:
private static final String FOLDER = "Foo";
#Test(groups = FOLDER)
public void test() {
//create the folder named FOLDER
}

You can get the annotation from a Method (which you can get from the Class.get{,Declared}Methods() method):
Test test = method.getAnnotation(Test.class);
This will be non-null if the annotation was present, and null if it was not. If it is non-null, you can then just call the groups() method on test:
String groups = test.groups();

Why not using a #BeforeMethod method?
#BeforeMethod
public void generateFolderFromGroups(Method m) {
Test test = m.getAnnotation(Test.class);
String[] groups = test.groups();
// generate folder from groups
}
#Test(groups = "Foo")
public void test() {
// the Foo folder will be already created
}

Related

Unit test file content creation before it being deleted

I have the following JAVA code:
#Override
public void myFunc(...) {
String content = createFileContent(...);
File f = createFile(content);
uploadFile(f);
deleteFile(f)
}
I want to test to file content, or the file itself (both can work), using unit test.
The file is deleted before the function ends.
What is the approach you would recommend on taking here? (I am using Mockito as mocking framework)
Spy the target test class and define the behavior and verify the calls of the methods, and if you want to assert the argument you can use ArgumentCaptor
public class TargetTest {
#Test
public void shouldDoSomething() {
// Arrange
final String content = "content-file";
final File file = new File();
Target target = spy(target);
doReturn(content).when(target).createFileContent();
doReturn(file).when(target).createFile(content);
doNothing().when(target).uploadFile(file);
doNothing().when(target).deleteFile(file);
// Act
target.myFunc();
// Assert
verify(target).createFileContent();
verify(target).createFile(content);
verify(target).uploadFile(file);
verify(target).deleteFile(file);
}
}

Load properties based on test annotation

is there a way to tell a Test with annotations or something like that, to load properties based on a custom annotation and run the tests equally to the number of parameters that test has.
For example:
I want to run test A that has values injected with Spring #value , three times, and for run 1 I want the test to get the values from property file X for run 2 from property file Y and you got it, run 3 from property file Z.
#Value("${person.name}")
private String person.name;
#RunTestWithProperties(properties = {X,Y,Z})
#Test
public void testA() {(System.out.println(person.name); }
On the first run, this test would print the person.name from X
properties file, on the second run the test would print the
person.name from Y and so on.
What would be expected:
testA runs 3 times(each run with different properties) from files X, Y and Z;
I could use data providers or something like that, load properties with system variables but it is not the solution I want.
Technologies I use are Java, TestNG and Spring. Any solution is more than welcomed.
Thank you in advance guys!
You can use parameterized tests. You need to create a method annotated with #Parameterized.Parameters where you can load all you data in a collection (Basically the parameters you need to pass for each run).
Then create a constructor to pass the arguments and this constructor argument will be passed from this collection on each run
e.g.
#RunWith(Parameterized.class)
public class RepeatableTests {
private String name;
public RepeatableTests(String name) {
this.name = name;
}
#Parameterized.Parameters
public static List<String> data() {
return Arrays.asList(new String[]{"Jon","Johny","Rob"});
}
#Test
public void runTest() {
System.out.println("run --> "+ name);
}
}
or if you don't want to use constructor injection you can use #Parameter annotation to bind the value
#RunWith(Parameterized.class)
public class RepeatableTests {
#Parameter
public String name;
#Parameterized.Parameters(name="name")
public static List<String> data() {
return Arrays.asList(new String[]{"Jon","Johny","Rob"});
}
#Test
public void runTest() {
System.out.println("run --> "+ name);
}
}

How to read variable from application.properties from method that is testing

I have class:
#Service
public class A {
#Value("${a.b.c}")
private String abc;
public void foo() {
sout(abc);
}
}
I Have test class:
#SpringBootTest
#SpringBootConfiguration
#RunWith(SpringRunner.class)
#TestPropertySource(locations = "classpath:application.yml")
public class TestA {
#Value("${a.b.c}")
private String abc;
#InjectMocks
private A a;
#Test
public void testFoo() {
this.a.foo();
}
}
When I debugging the test method testFoo(),
I see that variable abc is read from the application.yml file.
But,
inside the foo() method,
I see that the variable abc is null.
How can I set variable abc such that it is available in method foo() when I trying to test this method?
Step one is to answer this question: Am I unit testing the code in my class or am I integration testing the combination of Spring and some collection of code that includes my class?
If you are unit testing your code,
then it is not necessary to have Spring do its thing.
Instead,
you only need to instantiate your class,
set the values that Spring would have set for you,
execute the method you are testing,
then verify that your method executed correctly.
Here is your example unit test rewritten as I suggested:
public class TestA
{
private static final String VALUE_ABC = "VALUE_ABC";
private A classToTest;
#Test
public void testFoo()
{
classToTest.foo();
}
#Before
public void preTestSetup()
{
classToTest = new A();
ReflectionTestUtils.setField(
classToTest,
"abc",
VALUE_ABC)
}
}
Some Notes:
ReflectionTestUtils is part of Spring-test.
You don't need to use #InjectMocks because you have no mocks to inject.
I don't know what sout is, so I excluded it from the test. You should verify that the sout method was called with the correct value (in this case VALUE_ABC).
If you are just unit testing your code, you don't need Spring, which means that you don't need to use the #RunWith annotation.
You can try to overide the properties like that:
#TestPropertySource(locations = "location.properties",
properties = "a.b.c=123")
Example taken from here

How to mock a file required by a Bean at initialization in JUnit tests

I have a Bean that is reading a file at initialization. The file is environment specific and is generated during the installation of the system. The path of the file is hardcoded as a final static variable in the code.
private static final String FILE_PATH = "/etc/project/file.path";
private String decryptedPassword = "";
#Autowired
public ClassToBeTested(#Value("${pass}") String encryptedPassword)
{
String decryptedPassword = StaticClass.decrypt(encryptedPassword, FILE_PATH);
}
I need to somehow mock this file in the JUnit tests so that I can test the rest of the functionalities. The #Before annotation is not useful because even that is run after initialization of the Beans according to my tests.
One very dirty way that can be used is to add another parameter to the Autowired function that can indicate if the call is for a unit test or not. But this is really not a clean way to do this. For example:
private static final String FILE_PATH = "/etc/project/file.path";
private String decryptedPassword = "";
#Autowired
public ClassToBeTested(#Value("${pass}") String encryptedPassword,
#Value("${isTest}") boolean isTest)
{
if (isTest)
decryptedPassword = encryptedPassword;
else
decryptedPassword = StaticClass.decrypt(encryptedPassword, FILE_PATH);
}
Any ideas how I can mock the file at FILE_PATH so that I do not have to use this workaround or force a property in the Autowired function without changing the Bean constructor?
You can use a tool like Whitebox to swap the FILE_PATH in your test context.
public class MyClass {
private static String MY_STRING = "hello";
public void whatsMyString() {
System.out.println(MY_STRING);
}
}
Note that MY_STRING is not final
#Test
public void testWhiteboxSwap() {
MyClass test = new MyClass();
test.whatsMyString();
String testContextString = "\tgoodbye";
Whitebox.setInternalState(MyClass.class, testContextString);
test.whatsMyString();
}
Console output:
hello
goodbye
You may still need to play with the #Before or #BeforeClass in your test structure to get the timing right, but Whitebox can facilitate the behavior you're looking for.
Be aware that this is not a threadsafe solution. If multiple tests change the static reference the last one will win!
I use a maven project for my sample. I've attached the pom addition below.
<dependency>
<groupId>org.powermock.tests</groupId>
<artifactId>powermock-tests-utils</artifactId>
<version>1.5.4</version>
</dependency>
In my specific case, the only way that I found was to refactor the code.

Is there a way to get method meta data when using #BeforeMethod in TestNG?

I am using TestNG and have a suite of tests. I want to perform an action before every test method that requires information about the method. As a simple example, say I want to print the name of the method before its executed. I can write a method annotated with #BeforeMethod. How can I inject parameters into that method?
Take a look at the dependency injection section in the documentation. It states that dependency injection can be used for example in this case:
Any #BeforeMethod (and #AfterMethod) can declare a parameter of type java.lang.reflect.Method. This parameter will receive the test method that will be called once this #BeforeMethod finishes (or after the method as run for #AfterMethod).
So basically you just have to declare a parameter of type java.lang.reflect.Method in your #BeforeMethod and you will have access to the name of the following test name. Something like:
#BeforeMethod
protected void startTest(Method method) throws Exception {
String testName = method.getName();
System.out.println("Executing test: " + testName);
}
There's also a way by using the ITestNGMethod interface (documentation), but as I'm not exactly sure on how to use it, I'll just let you have a look at it if you're interested.
Below example shows how to get params when using data provider, using Object[] array in #BeforeMethod.
public class TestClass {
#BeforeMethod
public void beforemethod(Method method, Object[] params){
String classname = getClass().getSimpleName();
String methodName = method.getName();
String paramsList = Arrays.asList(params).toString();
}
#Test(dataProvider = "name", dataProviderClass = DataProvider.class)
public void exampleTest(){...}
}
public class DataProvider {
#DataProvider(name = "name")
public static Object[][] name() {
return new Object[][]{
{"param1", "param2"},
{"param1", "param2"}
};
}
}
Below example explains how you can get the method name and class name in your before Method
#BeforeMethod
public void beforemethod(Method method){
//if you want to get the class name in before method
String classname = getClass().getSimpleName();
//IF you want to get the method name in the before method
String methodName = method.getName()
}
#Test
public void exampleTest(){
}

Categories

Resources