Junit's #BeforeClass and #AfterClass must be declared static. There is a nice workaround here for #BeforeClass. I have a number of unit tests in my class and only want to initialize and clean up once. Any help on how to get a workaround for #AfterClass? I'd like to use Junit without introducing additional dependencies. Thanks!
If you want something similar to the workaround mentioned for #BeforeClass, you could keep track of how many tests have been ran, then once all tests have been ran finally execute your ending cleanup code.
public class MyTestClass {
// ...
private static int totalTests;
private int testsRan;
// ...
#BeforeClass
public static void beforeClass() {
totalTests = 0;
Method[] methods = MyTestClass.class.getMethods();
for (Method method : methods) {
if (method.getAnnotation(Test.class) != null) {
totalTests++;
}
}
}
// test cases...
#After
public void after() {
testsRan++;
if (testsRan == totalTests) {
// One time clean up code here...
}
}
}
This assumes you're using JUnit 4. If you need to account for methods inherited from a superclass, see this as this solution does not get inherited methods.
Related
I'm trying to test a method that calls an external util static method for a check, and need to somehow mock it to return true / false conditions, here is a sample:
class foo {
public void methodToTest(){
..logic
boolean myCondition = SomeUtil.checkCondition(args);
..more logic
}
}
Is this possible to do with mockito only? If not directly, is there a way to replace the SameUtil method with reflection or something similar?
I saw people suggesting powermock, but they don't have mockito 3.x listed on their compatibility chart, is there a better option?
This seems like a pretty common case, not everything should be autowired or injected.
Option 1: factor out the static method call into a separate method and use Mockito spy:
class Foo {
public void methodToTest(){
checkCondition(args);
// ....
}
boolean checkCondition(Object args) {
return SomeUtil.checkCondition(args);
}
}
class FooTest {
#Spy
#InjectMocks
private Foo foo;
#Test
void methodToTest() {
//...
when(foo.checkCondition(yourArg)).thenReturn(true);
}
}
See the Spy documentation for more details:
Option 2: factor out verification into a class:
class ArgumentVerifier {
boolean checkArgument(Object args) {
return SomeUtil.checkCondition(args);
}
}
class Foo {
private ArgumentVerifier verifier;
public void methodToTest() {
verifier.checkArgument(args); // mock the verifier as you normally would
// ....
}
}
It is possible since Mockito 3.4.0: Mocking Static Methods With Mockito
But please be aware that:
injecting remains a more explicit way of expressing dependency on another object/service, especially external api
static helper methods rarely need to be mocked (especially if they depend only on their arguments)
This limits the number of cases where mocking a static method is the tool of choice, but it is worth having it under your belt.
I have just started learning JUnit very recently and came across the following problem.
Have a look at the following class
class MyClass {
String a;
public MyClass(String a) {
this.a=a;
String doSomething(String a) {
if( a.isEmpty() )
return "isEmpty";
else
return"isNotEmpty";
}
I want to test the above method for both the conditions. If I proceed with the general structure of writing testcases it will look something like this:
class MyClassTest {
MyClass myClass;
#BeforeEach
void setUp() {
myClass=new MyClass("sampleString");
}
#Test
void doSomethingTest() {
Assertions.equal("isNotEmpty", myClass.doSomething());
}
}
However, for testing the empty string condition I will need another setup method where instead of "sampleString" I pass an empty string.
Following are the approaches I could think of and the questions for each:
Not use setUp at all and instead initialize the class in the individual test method. However, if let's say there are 10 testcases; 5 of which require empty string and rest "sampleString" then this doesn't make sense. Again, we can have a separate method for this repetitive code and call it individually in each testcase but then that defeats the purpose of having a steup method. Lets say I wanted to use two different setup methods, is there a way to do so?
Have a parameterized setup. I don't know if this is possible though. If yes, please share some useful links for this.
Use TestFactory. I tried reading up about this, but couldn't find an example for this specific case. If you have any, please share.
This example has been kept simple for illustrative purposes.
Group the tests with the same setup in an inner class annotated with #Nested. Each nested test class can have its own setup in a local #BeforeEach method.
You can always prepare the non-common data inside your test method. I've always thought it's easier this way, compared to using parameterized tests. You can't mix parameterized and non-parameterized tests in 1 file.
#Test
void doSomething_nullString()
{
myClass = new MyClass(null);
Assert.assertNull(myClass.doSomething());
}
#Test
void doSomething_emptyString()
{
myClass = new MyClass("");
Assert.assertEquals("", myClass.doSomething());
}
#Test
void doSomething_nonEmptyString()
{
myClass = new MyClass("sampleString");
Assert.assertEquals("sampleString", myClass.doSomething());
}
Or, you can always have helper methods inside the test class.
private MyClass createTestObject_nonNullString() {
return new MyClass("nonNullString");
}
private MyClass createTestObject_nullString() {
return new MyClass(null);
}
#Test
public void doSomething_sample() {
MyClass test = createTestObject_nonNullString();
// perform test
}
I have a static method (foo) that calls another static method (bar). I would like to mock the response of bar in my test. Is this possible with PowerMockito or another tool? the only results I can find are for mocking statics inside of non-static methods.
public class SomeClass {
static List<String> foo() {
...
int barResult = bar();
...
}
static int bar() {
// make a database call
return DAO.getDao().runQuery();
}
}
And my test will call it like:
#RunWith(PowerMockRunner.class)
public class SomeClassTest {
#PrepareForTest(SomeClass.class)
#Test
public void fooTest() {
List<String> actualResult = SomeClass.foo();
assertTrue(...);
}
}
Am I going to have to mock the internals of bar? So mock the DAO?
You can't do that.
Only PowerMock allows you to mock static methods. But that works by "erasing" all static things within that class that gets "prepared" for testing by PowerMock.
If you were talking about ordinary methods, you could be going for Mockito spies, as those allow for partial mockings.
And just for the record: simply avoid using static, as using it leads to "hard to test" code.
In other words: instead of using the big ugly powermock hammer to "fix" your design problems... Consider fixing your broken design instead and thereby avoiding the need for PowerMock altogether!
And for the record: yes, you could solve your problem by mocking that static call on the DAO class (then you can control what bar() does indirectly. But again: that would just mean to put the "I tested it" label on code that should be reworked instead.
You can do:
#RunWith(PowerMockRunner.class)
#PrepareForTest({SomeClass.class, DAO.class})
public class SomeClassTest {
#Test
public void fooTest() {
PowerMockito.mockStatic(DAO.class);
Mockito.when(DAO.getDao().runQuery()).return(..);
List<String> actualResult = SomeClass.foo();
assertTrue(...);
}
}
What is the recommended pattern to modify constants for unit tests? This is currently what I've used for some time and today I realized it's flawed.
Assume my class looks like this
class Foo {
private static final int MAX_TIME = Integer.getInteger("myProp", 1000);
...
}
The fact that I use a VM property is not only to modify it in a unit test. It is because I want it to be immutable from the actual code and I don't want to pollute a constructor with it since it is an implementation detail.
So, in production I want a timeout of 1 second; however that's too long for unit tests so I do this
class FooTest {
#Before
public void setUp() {
System.setProperty("myProp", "50");
}
#Test
public void testThatAssumesTimeoutOf50() { ... }
}
This worked fine for a long time until today I finally added a BarTest like this
class BarTest {
Foo mockFoo = mock(Foo.class); //actually done in a #Before method in the real code
}
Now what this created is that my tests fail or pass depending on the order of execution. If Foo is tested first, the test that assumes a testing timeout of 50ms passes. But if Bar is tested first then this makes Foo to be loaded due to the mock so MAX_TIME takes the default value of 1000 and then when BarTest ends and FooTest starts, the test that assumes a testing timeout of 50ms now fails.
The easiest way is probably to remove the final keyword. This will let you change the value after class loadtime.
Since you set and get the value across many different classes, and possibly packages, you should probably add a getter and setter. If you need to change this value across packages, then it will have to be public.
class Foo{
public static int getMaxTime(){
return MAX_TIME;
}
public static void changeMaxTime(int timeout){
//validation logic goes here
this.MAX_TIME = timeout;
}
Then, in your test classes, you should save the old value in the #BeforeClass or #Before phase, change it to whatever you want, and then restore the old value in the #AfterClass or #After phase.
Since it looks like you do this across many test classes, it might be best to actually make your own Test Rule:
public class TimeoutRule extends ExternalResource {
private final int oldTimeout, newTimeout;
public TimeoutRule(int timeout){
this.oldTimeout = Foo.getMaxTime();
this.newTimeout = timeout;
}
#Override
protected void before() {
}
#Override
protected void after() {
//restore old timeout
Foo.setMaxTimeOut(oldTimeout);
}
}
Then in your test code:
class FooTest {
#Rule
public TimeoutRule timeoutRule = new TimeoutRule(50);
#Test
public void testThatAssumesTimeoutOf50() { ... }
}
That code will reset the timeout to 50 ms and then restore it to the original value after every test. If you wanted to only do it once per test class, use #ClassRule instead (and make the field static)
I have a method that is not a regular test method. It is a cleanup method. I want to run it after some methods (some methods that are not test methods but are called from some test methods ).
How can do that using JUnit4?
PS: After and AfterClass are not a choice. I want to run a method after "some" non test methods (some methods that are called within test methods).
have you tried #AfterClass And #After ,#Before ,#BeforeClass ?
for the case of #AfterClass your method should be static .
in these case your method would be launched once before all the Tests.
check this link.
junit-beforeclass-and-afterclass-behavior-in-case-of-multiple-test-cases
You will need to call those methods manually or through AOP if you are using Spring.
You could use a TestWatcher to listen to when the test has finished, & check the test-name to see if your code should be ran. E.g.:
#Rule
public TestRule runFooSomtimes = new TestWatcher() {
public void foo() {
//do stuff here
}
List<String> methodsToCheck = new ArrayList<String>() {{
add("testMethodOne");
}}
#Override
protected void finished(Description description) {
if(methodsToCheck.contains(description.getMethodName())) {
foo();
}
}
};
(Excuse any errors, away from an IDE at the moment, but should give an idea.)