i came across something interesting while running some unit tests. i have the following method:
private void createSchemaIfNecessary() throws SQLException, IOException{
if(!schemaExists){
try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement();) {
statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
connection.commit();
schemaExists = true;
}
}
}
each unit test calls this method to determine whether or not to create the tables. the schemaExists variable is a member variable. i noticed that as each test was running, there were cases where even after hitting the schemaExists = true; line, the next time the method was called, schemaExists evaluated to false. i then made the variable static, and that fixed the problem.
As the individual unit tests are running, don't they all run within the context of a single instance of the unit test class?
I'm going to assume schemaExists is a non-static member of your test class.
Before invoking a test method (annotated #Test), junit (by default) creates a new instance of your test class (More detail here).
Thus, any non-static class member will be initialized as per defined in the class If not explicitly initialized, then they'll be set to their defaults, so if schemaExists is a boolean (primitive) then false.
I'd suggest that what you want to do if you want to setup something for all tests to share is create a #BeforeClass static method to initialize a static property.
This will ensure it's run only once for the given test class, before any test methods are run
It's very clear to others reading your code what the intention was for the method
Here's an example with the DB schema initialization code in your OP:
#BeforeClass
public static void setupDBOnce() {
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
connection.commit();
}
If for some reason you don't want this behavior (one instance per test method run) you can do any of these:
Annotate your class with #TestInstance(Lifecycle.PER_CLASS)
Pass the following VM arg: -Djunit.jupiter.testinstance.lifecycle.default=per_class
Create or add to an existing property file named junit-platform.properties found in the source root of the class path the entry: junit.jupiter.testinstance.lifecycle.default = per_class
If you do override the default, one note worth remembering from the docs:
When using this mode, a new test instance will be created once per test class. Thus, if your test methods rely on state stored in instance variables, you may need to reset that state in #BeforeEach or #AfterEach methods.
Related
My Junit test code looks like this.
private static boolean setupDone = false;
private Box box;
#Before
public void setup(){
if (setupDone){
return true;
}
box = new BoxCreator(this.applicationContext);
applicationContext.getAutowireCapableBeanFactory().autowireBean(box);
setupDone = true;
}
#Test
public void Test1(){
String response = box.getBoxResponse();
...asserts go here as usual....
}
#Test
public void Test2(){
String response = box.getBoxResponse();
...asserts go here as usual....
}
Now what happens is that Setup method runs only once as desired by virtue of setupDone variable.
Setup method after creating an instance of Box object autowires it as seen in the code above. Intention is to have a singleton of this class and use the same instance in every test.
Now the problem is that whichever test method runs first gets the value of box object and the second test method sees box as null. Not sure why it becomes null when the second test method is executed.
I suspect its not using the same instance of the test class for each test method's run.
If you make "box" static, it might work better. Note that "setupDone" and "box" are initialized in the #Before method together and should reside in the same place whether its the class as for statics or the instance as for merely global variables.
The problem with that is that if one test modifies the state of the object or its inner objects, a following test might not work right.
As Lee Meador mentioned, JUnit creates a new instance of the test class before invoking each #Test method. By doing this it provides independence between test methods and avoids unintentional side effects in the test code. Each test should be individually executed without any effect of the previous test and hence should have different application contexts in your case.
I am having a build failure issue while running a bunch of unit test over a java project. I am getting the NoClassDefFoundError which is happening because of the lack of ability for the unit test to get the dependencies. I am trying to mock an object for the class and then call the function, but the code is structured in a way that is getting a bit complex for me to handle the issue. I am very new to unit testing. I have provided below, a sample of code structure that my project has
Class ServiceProvider(){
obj declarations;
public void mainFunction(){
//Does a couple of things and calls a function in another class
boolean val = subFunction();
}
public boolean subFunction(){
boolean val = AnotherClass.someFunction(text);
//this function throws lots of exceptions and all those are caught and handled
return val;
}
#RunsWith(MockitoJUnitRunner.class)
Class UnitTestBunch(){
#Mock
AnotherClass acObj = new AnotherClass();
#InjectMock
ServiceProvider sp = new ServiceProvider();
#Test
public void unitTest1() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
#Test
public void unitTest2() throws Exception{
thrown.expect(ExceptionName.Class);
sp.mainFunction();
}
I have a test that uses the mock object and performs the function call associated with that class. But, the issue here is that there are a bunch of other unit test cases that are written similar to the unitTest2 function and calls the mainFunction at the end of the test. This mainFunction invokes someFunction() and causes NoCalssDefFoundError(). I am trying to make the unit test execute the content in unitTest1 everytime when it sees the AnotherClass.someFunction(). I am not sure if this is achievable or not. There could be another better way to resolve this issue. Could someone please pitch in some ideas?
In your test you seem to be using unitTest1 for setup, not for testing anything. When you run a unit test, each test should be able to run separately or together, in any order.
You're using JUnit4 in your tests, so it would be very easy to add the statement you have in unitTest1 into a #Before method. JUnit4 will call this method before each test method (annotated with #Test).
#Before
public void stubAcObj() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
The method may be named anything, though setUp() is a common name borrowed from a method to override in JUnit3. However, it must be annotated with org.junit.Before.
If you need this from multiple test cases, you should just create a helper, as you would with any code. This doesn't work as well with #InjectMocks, but you may want to avoid using #InjectMocks in general as it will fail silently if you add a dependency to your system-under-test.
public class AnotherClassTestHelper {
/** Returns a Mockito mock of AnotherClass with a stub for someFunction. */
public static AnotherClass createAnotherClassMock() {
AnotherClass mockAnotherClass = Mockito.mock(AnotherClass.class);
when(mockAnotherClass.someFunction(text)).thenReturn(true);
return mockAnotherClass;
}
}
As a side note, this is a counterintuitive pattern:
/* BAD */
#Mock
AnotherClass acObj = new AnotherClass();
You create a new, real AnotherClass, then instruct Mockito to overwrite it with a mock (in MockitoJUnitRunner). It's much better just to say:
/* GOOD */
#Mock AnotherClass acObj;
In a Junit test, is it possible to test for variables in the main method?
My main method something like this looks like this:
package edu.blah.class.project1;
public class Program {
public static void main(String[] args) {
try {
int result = Utility.analyze();
} catch (Exception e) {
System.out.println("Error");
}
}
}
Is it possible to obtain the variable result in a JUnit class? Is the only way to make it a public variable? Thanks!
In a Junit test, is it possible to test for variables in the main method?
Err ... no. Unless you have a JUnit test that calls the main method explicitly, then the main method won't be called in a unit test.
Besides, the variable here is result which is a local variable, and there is no way to reach into a method to test some local variable. (Java simply doesn't allow it ...)
Is it possible to obtain the variable result in a JUnit class?
In this example, result gets the value of the call Utility.analyze(). There is no reason why a JUnit test could not do that too ... and thereby get the same value. (Or at least it could in this example.)
Is the only way to make it a public variable?
No ... see above.
However, if you are actually trying to test the value of result in the context of the main method, then you are right. The only way to get hold of the value would be to expose it as a static variable. It doesn't necessarily have to be public static though. (Indeed, if you were prepared to write do some "nasty" reflection you could even get your JUnit test to extract and test the value of a private static field.)
However, I think you are taking the wrong approach top this. Rather than trying to figure out how to reach into a static method (or any method), it would be better if you restructured the code to make it more testable. For example:
package edu.blah.class.project1;
public class Program {
public int run(String args[]) {
return Utility.analyze();
}
public static void main(String[] args) {
try {
new Program().run(args);
} catch (Exception e) {
System.out.println("Error");
}
}
}
With a small amount of restructuring (like this), you can make it a lot easier to write unit tests for all of the important functionality. You are left with the "problem" it is still hard to unit test the main method. However, you have reduced the method to the point that it is so simple that you can verify it is correct by visual inspection: unit testing main is now unnecessary.
No, local variables are allocated on stack and are not available outside the method.
Your wishing to check the local variable from test means that you probably should split your method into several smaller ones. Generally this is one of the principals of TDD - Test Driven Development.
Unit tests can call any accessible method, including the main method. Apart from it being recognized as an application entry point there is nothing special about the main method.
Regarding how to test your example, in the current state the local variable result cannot be accessed. Before resorting to all sorts of tricks to access it, ask yourself the question why you would want to test for it?
A unit test should check the contract of a method, which comprises of the input parameters, the return value and any side effects. Testable side effects are:
changing the state of the encompassing class
calling instances of classes that are fields in the class under test
Hard to test side effects are:
static calls
direct interaction with the environment like the file system, network, threads
behavior depending on system time
In most cases the situations that are hard to test can be avoided by refactoring your application, making it more testable.
However, in your example none of the above applies. The local variable 'result' is not used for anything. So in the current state of your application you don't have to (and cannot) test for its value.
When I use my imagination to guess what your application could/should be doing an extended and testable version may look something like this:
public class Program {
public static final String ERROR_MESSAGE = "Error";
// Utility modeled as a dependency to avoid static access
private Utility utility;
// a poor man's logger, better to use a logging framework like log4j
private PrintStream logger;
// 'business logic' extracted into a separate method to be tested
public void execute(String[] args) {
try {
// static access to Utility replaced with instance access
// passing the args to make testing more interesting
int result = utility.analyze(args);
// added logging of the result to make testing more interesting
logger.println(result);
} catch (Exception e) {
// Static access to System.out replaced with logger instance
logger.println(ERROR_MESSAGE);
}
}
// setters used for dependency injection
public void setUtility(Utility utility) {
this.utility = utility;
}
public void setLogger(PrintStream logger) {
this.logger = logger;
}
// application entry point does basic initalization and depency injection
public static void main(String[] args) {
// create application instance
Program program = new Program();
// inject dependencies
program.setUtility(new Utility());
program.setLogger(System.out);
// call application
program.execute(args);
}
}
And the unit test, using JUnit4:
import static org.mockito.Mockito.*;
import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.*;
#RunWith(MockitoJUnitRunner.class)
public class ProgramTest {
// #InjectMocks creates an instance and injects any specified mocks
#InjectMocks
private Program instance;
// #Mock creates a mock instance, which can be used to specify behavior using when() and verify access using verify()
#Mock
private Utility utility;
#Mock
private PrintStream printStream;
// #Test indicates a test method in JUnit4
#Test
public void testExecuteHappy() {
// SETUP
String[] args = new String[];
int expectedResult = 42;
// specify behavior of the Utility mock to return the expected result
when(utility.analyze()).thenReturn(expectedResult);
// CALL
instance.execute(args);
// VERIFY
// check that utility.analyse() was called with the args
verify(utility).analyze(args);
// verify that logger.println() was called with the expected result
verify(logger).println(expectedResult);
}
#Test
public void testExecuteError() {
// SETUP
String[] args = new String[];
// specify behavior of the Utility mock to throw an exception
when(utility.analyze()).doThrow(new Exception("test exception));
// CALL
instance.execute(args);
// VERIFY
// check that utility.analyse() was called with the args
verify(utility).analyze(args);
// verify that logger.println() was called with the error message
verify(logger).println(Program.ERROR_MESSAGE);
}
}
Typically dependencies require additional configuration like which database to access, connection pools etc. In a larger application dependency injection would be done by a framework like Spring or CDI rather than the main method.
Here are the Maven dependencies needed for this:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
Add these to your pom.xml. If you don't use Maven, download these .jar files and add them to the class path used for compilation:
Junit 4.11
Mockito core 1.9.5
Note: I didn't compile or test the above code so there might be small typo's
I'm creating a series of unit tests for an EJB application which uses JPA for the database persistence layer. As these are unit tests I'm treating the EJB beans as POJOs and using Mockito to mock the EntityManager calls.
The issue I've encountered is that one of the methods in my class under test changes a value in the entity before calling the EntityManager merge(...) method to save the entity, but I can't see how the unit test is able to check whether the method being tested did actually change the value.
Whilst I could add another when(...) method so that the merge(...) method returns an instance of the entity with the modified value, I don't think this would be of any benefit as it wouldn't actually test that the class under test had modified the value and would defeat the purpose of the test.
The method in my class under test is as follows:
public void discontinueWidget(String widgetId) {
Widget widget = em.find(Widget.class, widgetId);
//Code that checks whether the widget exists has been omitted for simplicity
widget.setDiscontinued(true);
em.merge(widget);
}
The code in my unit test is as follows:
#Mock
private EntityManager em;
#InjectMocks
private WidgetService classUnderTest;
#Test
public void discontinueWidget() {
Widget testWidget = new Widget();
testWidget.setWidgetName("foo");
when(em.find(Widget.class, "foo")).thenReturn(testWidget);
classUnderTest.discontinueWidget("en");
//something needed here to check whether testWidget was set to discontinued
//this checks the merge method was called but not whether the
//discontinued value has been set to true
verify(em).merge(testWidget );
}
As the Widget class isn't being mocked I can't call something along the lines of verify(testWidget).setDiscontinued(true);
My question is how can I check whether the discontinueWidget(...) method in the class under test has actually set the discontinued variable in the Widget class to true?
I'm using JUnit version 4.12 and Mockito version 1.10.19.
You can declare the Widget in your test as being a mock also, and verify on it.
Widget testWidget = mock(Widget.class);
when(em.find(Widget.class, "foo")).thenReturn(testWidget);
classUnderTest.discontinueWidget("en");
//something needed here to check whether testWidget was set to discontinued
verify(testWidget).setDiscontinued(true);
//this checks the merge method was called but not whether the
//discontinued value has been set to true
verify(em).merge(testWidget );
Like the title says I keep getting fields that are null down in the test cases even though I've initiated them in the #Before method as a one-time set-up. The only exception is that the first test that runs, works.
I was able to replicate the behaviour with the following code:
public class NetworkTest extends TestCase{
private static Boolean oneTimeSetUpDone = false;
private Client client;
#Before
public void setUp(){
if(!oneTimeSetUpDone){
client = new Client();
oneTimeSetUpDone = true;
}
}
#Test
public void testConnection(){
System.out.println(client);
assertFalse(true);
}
#Test
public void testMultiConnection(){
System.out.println(client);
assertFalse(true);
}
Am I missing something here or why would the fields get cleared after the first test is run?
#Before is run before each test - you should think of every #Test running in a new instance of the test class, and #Before sets up that instance (pro tip: look at the class' .hashCode() - it's different in each test method).
You can use #BeforeClass in your case.
Cheers,
Each test case in your test class, gets it's own copy of the instance variables. However your static field
private static Boolean oneTimeSetUpDone = false;
is shared among all the test cases. For each test case, the #Before method is execuded. What happens is that you're initializing the instance fields only for the first case - it's the if statement that sets the above flag to true, thus leaving the instance variables for other test cases uninitialized.
You have two options, depending on the instance fields. First answer this question, does it make sense to reuse the same instance field objects for each test case?
If it does, you could make them static, and your #Before method shall do fine as it is now.
Otherwise, you should remove the boolean flag, along with the if statement. That is, you need to initialize the instance variables for each test case, since they need to be "fresh" for each test case.
P.S. make your boolean field simply boolean instead of Boolean.