Execute code before #Before method for JUnit test - junit

I need to execute some code before the #Before method of each unit test is executed. The problem is that I also need to know which test (the name is sufficient) will be executed afterwards.
I can either use AspectJ or Java Agents with bytecode manipulation to achieve this. Also the solution should work for tests where there is no #Before annotation present.
Any ideas?
EDIT: I can't modify the unit tests themselves, as I'm developing a framework for executing tests of other projects

You might want to look into the TestName rule in JUnit:
http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestName.html
About the ordering, a solution could be to define a super class for your tests and put a #Before in there, as #Before methods in super classes are run before those in sub classes.

If you want to write a Java agent and you are not bound to Javassist or AspectJ, have a look at Byte Buddy for doing so. You can add the code in the MyAdvice class to any method annotated with #Test given that the type name ends with Test (as an example) by:
public class MyAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(nameEndsWith("Test"))
.transform((type, cl, builder) -> builder.visit(Advice
.to(MyAdvice.class)
.on(isAnnotatedWith(Test.class)))
.installOn(instrumentation);
}
}
class MyAdvice {
#Advice.OnMethodEnter
static void enter() {
System.out.println("foo");
}
}
Just bundle the above code to a Javaagent with the proper manifest code and register it before running. If you are running on a JDK, you can also attach the agent programmatically using the byte-buddy-agent project.

Related

Is there a way to share #Before code between tests suite classes?

I am testing a Cordova plugin in Java/Android and I need to initialize my Plugin class and set some state before I run my Tests.
#Before
public void beforeEach() throws Exception {
System.out.println("Creating new Instance ");
PowerMockito.mockStatic(Helpers.class);
PowerMockito.when(Helpers.canUseStorage(any(), any())).thenReturn(true);
MyLogger myLoggerMock = PowerMockito.mock(MyLogger.class);
PowerMockito.doNothing().when(myLoggerMock, "log", anyString());
PowerMockito.whenNew(MyLogger.class).withAnyArguments().thenReturn(myLoggerMock);
this.sut = spy(new FilePicker());
PowerMockito.doNothing().when(this.sut).pick(any(), any());
}
I want to create a Test Suite / Java Class per public function, but I do not want to repeat that code every time.
Is there a way to share that before each between test suites? I have found ClassRule but I think I do not do what I need (or I am understanding it wrong... I am really new in Java)
In Typescript we can share beforeEachfunctions with several suites, and each suite can have their own beforeEach
One possible ways is using inheritance:
Make all test classes extend from one "parent test" class and define a #Before in a parent class.
So it will be called automatically for all the subclasses:
public class ParentTest {
#Before
public void doInitialization() {
....
}
}
public class Test1Class extends ParentClass {
#Test
public void fooTest() {
// doInitialization will be executed before this method
}
#Test
public void barTest() {
// doInitialization will be executed before this method as well
}
}
Two notes:
Note 1
In the code you use sut (subject under test) - this obviously should not be in the parent's doInitialization method, so its possible that Test1Class will also have methods annotated with #Before (read here for information about ordering and so forth)
Then the `sut gets initialized with Spy which is frankly weird IMHO, the Subject Under Test should be a real class that you wrote, but that's beyond the scope of the question, just mentioning it because it can point on mistake.
Note 2
I'm writing it in an an attempt to help because you've said that you're new in Java, this is not strictly related to your question...
While this approach works in general you should be really cautious with PowerMockito. I'm not a PowerMockito expert and try to avoid this type of mocks in my code but in a nutshell the way it manipulates the byte code can clash with other tools. From your code: you can refactor the HelperUtils to be non-static and thus avoid PowerMocking in favor of regular mocking which is faster and much more safe.
As for the Logging - usually you can compromise on it in unit test, if you're using slf4j library you can config it to use "no-op" log for tests, like sending all the logging messages into "nothing", and not-seeing them in the console.

What is the scope of the #SuppressStaticInitializationFor PowerMock annotation?

Does anyone know what is the scope of this annotation? For example, if I have multiple JUnit test classes that run sequentially in the same VM, and the first test uses #SuppressStaticInitializationFor, does that suppress the static initialization for all the subsequent test classes, too? I ask because I am under the impression that static state persists for the life of the JVM.
The scope is per classloader. Once you've used #SuppressStaticInitializationFor it'll affect the class in all other tests. You can however #SuppressStaticInitializationFor at the method level instead and that way it won't affect other tests.
you can use #SuppressStaticInitializationFor annotation at the class-level or at the method-level of the test where you want it to be suppressed.
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor("com.main.java.CassName")
public class TestClassName extends PowerMockTestCase {
//code
#SuppressStaticInitializationFor("com.main.java.AnotherClassName")
public void testMethod() {
//code
}
}
This way you can control which method should suppress static initializers(constructors) and for which class.

Why Junit still allow a class extend TestCase to use the annotation #Test in it?

I know in Junit, the class extend TestCase cannot support #Before and #After. But it still allow to use #Test?
I know without #Test, if we want to run this class, we could override the runTest method and define the method to be invoked. This is not convenient. Because if we mark the #Test in method of this class., it could run directly. Can anyone tell me the mechanism about how to invoke the method with #Test about this class?
By the way, If I want put a lot of tests into a TestSuite, Should I choose a class extend TestCase or define a arbitrary class with #Test as the Single Test Class ?
The TestCase class is from Junit 3 and should not be used in Junit 4 + classes.
If you extend TestCase, and use the Junit 3 Test runners then your test method names need to start with the word "test". (Junit 3 test runners use Java reflection to find and invoke all methods that start with the word "test")
Relying on TestClass hindered test class designs because you were forced to extend that class which made somethings hard to test. There also wasn't anything equivalent to Junit4's #BeforeClass or #AfterClass which meant you had to do all the more complicated multi-test fixture set up and tear down yourself.
To run many Junit4 test classes at once as a Test Suite, you can create a new empty class with the #RunWith and #SuiteClasses annotations as shown below:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses(
{
TestClassA.class,
TestClassB.class
}
)
public class MyTestSuite{
}

How to Create a "Base" Test Method in Junit or TestNG

Given the following:
class TestCase {
#Test
public void test(){
assertTrue(true);
}
}
Is there a way to create a base test method? I have some repetitive code that needs to happen for each test. Or perhaps I am just as well-off writing a utility method and calling it each time in the beginning of each test?
It can't be in a #beforeMethod because I need the info in the test itself.
Sure, just put it in a base class and extend that class (at least for TestNG).

Eclipse JUnit #Before annotation problem

I'm experiencing some difficulties using JUnit 4.5 in Eclipse, when I use #Before annotation it just does nothing (I may use setUp() which works of course, but I'm just wondering what is wrong), while it works perfectly in Netbeans.. Any thoughts?
Because I cam here via a Google Search, and had to dig quite a bit deeper to see the actual solution:
As #Pace said in the comments, if you extend TestCase, Eclipse treats the Test as JUnit Version 3 or older, and does not respect the #Before annotation - also descripred here: JUnit + Maven + Eclipse: Why #BeforeClass does not work?
Hence, removing the extend TestCase causes fixes the problem
If you are using JUnit 4, you can just annotate the test class or the test method with #Test annotation, instead of extending TestCase.
Since you are using JUnit 4+ there are two ways to write a test case
1 > You make your test class extend TestCase. In this case classes corresponding to Junit 3 are picked up which are not aware of #Before annotation. In this case you will have to override
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*/
protected void setUp() throws Exception {
}
2 > use annotations. use #Test annotation for the method in the test class that you are interested in running as a test. There is no need for your class to extend TestCase. Also you do not have to override any method. Simply define your own method that has the logic to be executed before the test method runs and annotate it with #Before annotation.