Unit Testing with modifying static variables during initialization - java

I have a class that has static variables assigned during initialization. I would like to write unit tests for this class with modifying values for this static variable. Below is a simple code to explain my scenario
Class to test:
public class Hello {
private final static String HELLO_FINAL = "Hello " + HelloTo.getInstance().getHelloTo(); // I would like to modify this value between tests
public String sayHello() {
return HELLO_FINAL;
}
}
Supporting class:
public class HelloTo {
private String helloTo = "World";
private static HelloTo singleton = new HelloTo();
private HelloTo() {}
public static HelloTo getInstance() {
return singleton;
}
public void setHelloTo(String helloTo) {
this.helloTo = helloTo;
}
public String getHelloTo() {
return helloTo;
}
}
Test class:
import org.junit.Assert;
import org.junit.Test;
public class HelloTest {
#Test
public void testDefault() {
Assert.assertEquals("Hello World", new Hello().sayHello());
}
#Test
public void testDynamic() {
HelloTo.getInstance().setHelloTo("My name");
Assert.assertEquals("Hello My name", new Hello().sayHello());
}
}
Is there a way to make both tests successful. Currently I get a failure for testDymanic() saying:
org.junit.ComparisonFailure: expected:<Hello [World]> but was:<Hello [My name]>
Thanks in advance!

Using a mutable singleton in a tests is an known problem. You have to reset the state of the singleton between tests, of even better, don't use a singleton in your tests.
You could do something like:
public enum HelloTo {
INSTANCE;
private String helloTo = "World";
public void reset() {
setHelloTo("World");
}
public void setHelloTo(String helloTo) {
this.helloTo = helloTo;
}
public String getHelloTo() {
return helloTo;
}
}
public class Hello {
public static String sayHello() {
// has to be dynamic as helloTo can change.
return "Hello " + HelloTo.INSTANCE.getHelloTo();
}
}
public class HelloTest {
#Before
public void setUp() {
HelloTo.INSTANCE.reset();
}
#Test
public void testDefault() {
Assert.assertEquals("Hello World", Hello.sayHello());
}
#Test
public void testDynamic() {
HelloTo.INSTANCE.setHelloTo("My name");
Assert.assertEquals("Hello My name", Hello.sayHello());
}
}

HELLO_FINAL is only initialized once per run; you can't reinitialize it within the same JVM. Is there a way to make both tests successful? Sure, there are countless ways. But that depends on what you're trying to test, which is not completely clear from your example.

Related

How to verify a method was called inside another method with Mockito

I'm fairly new to Mockito, and I've been looking for a way to verify that if I call the filter() method with the right string, that the foo method will get called once.
public class A
{
private final Config _config;
public A(Config config) { _config = config; }
public void filter(String str)
{
if(str.startsWith("a"))
{
if(str.contains("z"))
{
foo(config.getName());
}
}
}
private void foo(String bar)
{
(...)
}
}
Here is my current code:
#Test
public void testOne()
{
Config config = new Config(configFile);
A a = Mockito.spy(new A(config));
a.filter("abcz");
verify(a, times(1)).foo(someString);
}
Try to be more generic while such a test. If you don't need to specify what exactly argument should by passed then just use any():
import static org.mockito.ArgumentMatchers.any;
verify(a).foo(any(String.class));

Spy an already initialized Java object Mockito

I am using the Mocktio library to write some test cases, since I have an elaborate inhertance structure, I have a few objects which are instantiated in the parent class, and I would like to mock one of its function call. Does Mockito library provide any way to spy on a already initialized object?
Also, the object is not directly instantiable.
Similar to the following -
public class A {
protected static MyObject a;
public static void someMethod() {
a = myObjectBuilder.createObj();
}
}
And another class B looks something similar to
class B extends A {
#BeforeClass
public static void setUpBeforeClass() {
someMethod();
}
#Test
public void mockTest() {
// now mock behavior of some method of MyObject a
// Missing line to spy object a.
Mockito.doReturn(false).when(a).xyz();
/* Now call some method that triggers a.xyz()
again, it is not a direct call,
there are multiple layer of abstraction
*/
}
}
Edit: I have tried the following and it does not work
MyObject mock_object = Mockito.spy(a);
Mockito.doReturn(false).when(mock_object).xyz();
Basically, don't do initialisation in BeforeClass, it runs only once but
you need to have new spy in each test, or you must "reinitialise" spy object
before each test.
Please examine this code:
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import static org.assertj.core.api.Assertions.assertThat;
class MyObject{
public String cos;
public MyObject(String cos) {
this.cos = cos;
}
public boolean xyz() {
return true;
}
}
class A {
protected static MyObject a;
public void someMethod() {
a = new MyObject("cccc");
}
}
public class B extends A {
#Before
public void setUpBeforeTest() {
someMethod();
}
#Test
public void mockTest() {
MyObject mock_object = Mockito.spy(a);
Mockito.doReturn(false).when(mock_object).xyz();
assertThat(mock_object.xyz()).isFalse();
}
#Test
public void mockTest2() {
MyObject mock_object = Mockito.spy(a);
Mockito.doReturn(true).when(mock_object).xyz();
assertThat(mock_object.xyz()).isTrue();
}
}
If you want it your way, please change:
public void someMethod() {
a = myObjectBuilder.createObj();
}
into:
public static void someMethod() {
a = myObjectBuilder.createObj();
}
You can't call non static method from static initialiser #BeforeClass:
class A {
protected static MyObject a;
public static void someMethod() {
a = new MyObject("cccc");
}
}
public class B extends A {
#BeforeClass
public static void setUpBeforeClass() {
someMethod();
}
#Test
public void mockTest() {
MyObject mock_object = Mockito.spy(a);
Mockito.doReturn(false).when(mock_object).xyz();
assertThat(mock_object.xyz()).isFalse();
}
#Test
public void mockTest2() {
MyObject mock_object = Mockito.spy(a);
// Here we replace original object with our spy
A.a = mock_object;
Mockito.doReturn(false).when(mock_object).xyz();
assertThat(a.xyz()).isFalse();
}
}
Another example (in this case we replace object a with mock (spy is not needed):
class MyObject{
public String cos;
public MyObject(String cos) {
this.cos = cos;
}
public boolean xyz() {
return true;
}
}
class A {
protected MyObject a;
public A() {
a = new MyObject("ggggg");
}
public String doSomethingWithA(){
if(a.xyz()){
return a.cos;
}
else{
return "aaaa";
}
}
}
#RunWith(MockitoJUnitRunner.class)
public class B {
#Mock
MyObject mock_object;
#InjectMocks
A systemUnderTest = new A();
#Test
public void mockTest1() {
Mockito.doReturn(false).when(mock_object).xyz();
assertThat(systemUnderTest.doSomethingWithA()).isEqualTo("aaaa");
}
#Test
public void mockTest2() {
Mockito.doReturn(true).when(mock_object).xyz();
assertThat(systemUnderTest.doSomethingWithA()).isNull();
}
}

JUnit test for getter method of custom object type

I need to write unit tests for my methods. I'm having a bit of trouble because I'm new to JUnit. I need to write a test for a getter method of an object type I created. The object type is UnitInfo, and I need to write a test for the method
#Override
public UnitInfo getInfo() {
return info;
}
in the class building. I put my building class, UnitInfo class and my buildingTest class in the code below. Any help is appreciated.
package main.model.facility;
import java.util.List;
public class UnitInfo {
private int capacity;
private String name;
private int idNumber;
private List<String> details;
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIdNumber() {
return idNumber;
}
public void setIdNumber(int idNumber) {
this.idNumber = idNumber;
}
public List<String> getDetails() {
return details;
}
public void setDetails(List<String> details) {
this.details = details;
}
public void addDetail(String detail) {
details.add(detail);
}
public void removeDetail(String detail) {
details.remove(detail);
}
}
Building class:
package main.model.facility;
import java.util.List;
public class Building extends Facility {
private List<IFacility<UnitInfo>> subunits;
private UnitInfo info;
private ScheduleManager schedule;
#Override
public UnitInfo getInfo() {
return info;
}
#Override
public ScheduleManager getScheduleManager() {
return schedule;
}
#Override
public List<IFacility<UnitInfo>> listFacilities() {
return subunits;
}
#Override
public int requestAvailableCapacity() {
int availableCapacity = 0;
for (IFacility<UnitInfo> subunit : subunits){
availableCapacity += subunit.requestAvailableCapacity();
}
return availableCapacity;
}
}
Junit
public class BuildingTest {
Building defaultBuilding = new Building();
ScheduleManager defaultSchedule = new ScheduleManager();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testGetInfo() { //this is the test I need to write
Building b = defaultBuilding;
assertEquals(b.getInfo(), null);
}
#Test
public void testGetScheduleManager() {
Building a = defaultBuilding;
assertEquals(a.getScheduleManager(), null);
}
Don't build your Building at the class level, create it inside the unit test so that each test has its own Building to work with. This way they won't interfere with each other.
Your test seems fine at the moment, you don't initialize info when you construct a new Building so info is null, and you are asserting that in your unit test. You could also use assertNull(b.getInfo());.
#Test
public void testGetInfo() { //this is the test I need to write
Building b = new Building()
assertEquals(b.getInfo(), null);
}
If you did initialize info to something else, say info = new UnitInfo(), then you could change your test to:
#Test
public void testGetInfo() { //this is the test I need to write
Building b = new Building()
assertNotNull(b.getInfo());
}
How about if, when you create a new Building you initialized info and set some of the fields.
info = new UnitInfo();
info.setIdNumber(100);
info.setName("Some Unit Info");
Then in your unit test you could assert that the fields were set:
#Test
public void testGetInfo() { //this is the test I need to write
Building b = new Building()
assertNotNull(b.getInfo());
assertEquals(b.getInfo().getIdNumber(), 100);
assertEquals(b.getInfo().getName(), "Some Unit Info");
}
The idea with unit tests is to exercise your code; call your methods and then assert that the results are what you expect. Once you have a good base of unit tests against all your code, you can feel confident about modifying it because you know that your tests will tell you when you break something.
Keep your tests small and simple, don't do too much. Just do your setup, call a method and make sure the results are correct. Then write a new test, and do something else. Don't write tests that do 5 different things.

Mocking simple property access with JMockIt

I have a simple get-set interface:
public interface Foo {
void setBaz(String baz);
String getProcessedBaz();
}
This interface is a dependency of my actual class under test. I'm trying to mock out Foo to have this effective behavior:
public class MockedFoo implements Foo {
private String bazField;
#Override
public void setBaz(String baz) {
bazField = baz;
}
#Override
public String getProcessedBaz() {
return "PROCESSED_" + bazField;
}
}
So my expected result is:
mockedFoo.setBaz("ABC");
assertEquals("PROCESSED_ABC", mockedFoo.getProcessedBaz());
I was able to capture the method argument using withCapture in a Verification, but how do I set up an Expectation with that same input value? It seems you can do either one or the other.
Is there a way to express this in JMockIt? I'm using the latest version (1.9).
NOTE: I'm aware that I can simply set up a Mockup<Foo> instance and put in all the code above. However, my real code is much more complex and I would prefer not to hand-craft the entire mock class.
You can do this using Delegate. You may try this
Class to test
public interface Foo {
void setBaz(String baz);
String getProcessedBaz();
}
class FooSubClass implements Foo {
private String bazField;
#Override
public void setBaz(String baz) {
bazField = null;
}
#Override
public String getProcessedBaz() {
return bazField;
}
}
Test class
import mockit.Capturing;
import mockit.Deencapsulation;
import mockit.Delegate;
import mockit.NonStrictExpectations;
import org.junit.Before;
import org.junit.Test;
public class FooTest
{
FooSubClass fooSubClass;
#Capturing Foo fooMocked;
#Before
public void setUp()
{
fooSubClass = new FooSubClass();
}
#Test
public void testAMethod()
{
new NonStrictExpectations()
{
{
fooMocked.setBaz(anyString);
result = new Delegate()
{
void setBaz(String baz)
{
Deencapsulation.setField(fooSubClass, "bazField", baz);
}
};
times = 1;
fooMocked.getProcessedBaz();
result = new Delegate()
{
String getProcessedBaz()
{
return "PROCESSED_" + Deencapsulation.getField(fooSubClass, "bazField");
}
};
times = 1;
}
};
fooSubClass.setBaz("abc");
System.out.println(fooSubClass.getProcessedBaz());
}
}
NOTE: This was inspired by Varun's answer, but I wanted to avoid using reflection and intermediate classes. Rogério also provided a viable alternative, but it did not fit into the overall structure of my test. Thanks to both!
Here's how I finally got it working:
public interface Foo {
void setBaz(String baz);
String getProcessedBaz();
}
#RunWith(JMockit.class)
public class FooTest {
#Injectable
private Foo mockedFoo = null;
#Test
public void testBaz() {
new Expectations() {
private String bazState; // Variable inside Expectations stores the state between calls
{
mockedFoo.setBaz(anyString);
result = new Delegate() {
void setBaz(String baz) { bazState = baz; }
};
mockedFoo.getProcessedBaz();
result = new Delegate() {
String getProcessedBaz() { return "PROCESSED_" + bazState; }
};
}
};
mockedFoo.setBaz("ABC");
assertEquals("PROCESSED_ABC", mockedFoo.getProcessedBaz());
}
}
One way to write such an state-based test is:
public interface Foo {
void setBaz(String baz);
String getProcessedBaz();
void someOtherMethod();
}
public static class ClassUnderTest {
String doSomething(Foo foo) {
foo.setBaz("ABC");
foo.someOtherMethod();
return foo.getProcessedBaz();
}
}
#Test
public void mockFoo() {
Foo foo = new MockUp<Foo>() {
String baz;
#Mock void setBaz(String baz) { this.baz = baz; }
#Mock String getProcessedBaz() { return "PROCESSED_" + baz; }
}.getMockInstance();
String res = new ClassUnderTest().doSomething(foo);
assertEquals("PROCESSED_ABC", res);
}
An equivalent test can also be written with the JMockit Expectations API (using Delegate objects), but it would be more verbose as that API is meant for behavior-based testing (ie, when you care more about which methods get invoked than state-transfer between objects).

How to cache a JUnit class field between runs with #Parameters

Lets assume the following JUnit test class:
#RunWith(Parameterized.class)
public class MyTestClass {
private ExpensiveObjectToCreate myObject;
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] {
{ "parameter1" },
{ "parameter2" },
};
return Arrays.asList(data);
}
#Test
public void test1() {
}
#Test
public void test2() {
}
public MyTestClass(String stringParameter) {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
}
Is there any way for me to create the expensive object just once for every parameter set? I say this because JUnit creates a new test class for every test it needs to run. This means that the expensive object is NOT created 2 times, but actually 4 times (2 parameter sets x 2 tests). This gets even worse when we have many test methods.
Also, sending the expensive object as a parameter is not a solution for me because my scenario is a little bit more complicated (I create the expensive object in JUnit rules).
Why not just roll out a custom cacher in your test case class, which caches the instance created per parameter and returns the same instance on further invocations.
#RunWith(Parameterized.class)
public class Test {
private static ExpensiveObjectCacher cacher; //instance which caches parameter instance
private ExpensiveObject myObject;
public Test(String value) {
this.myObject = cacher.get(value);
}
#BeforeClass
public static void setUpBeforeClass(){
cacher = new ExpensiveObjectCacher();
}
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] {
{ "parameter1" },
{ "parameter2" },
};
return Arrays.asList(data);
}
#org.junit.Test
public void test1(){
}
#org.junit.Test
public void test2(){
}
}
//caching for test cases.
class ExpensiveObjectCacher{
private Map<String, ExpensiveObject> map = new ConcurrentHashMap<String, ExpensiveObject>();
ExpensiveObject get(String value){
ExpensiveObject instance = map.get(value);
if(instance == null){
instance = new ExpensiveObject(value);
map.put(value, instance);
}
return instance;
}
}
class ExpensiveObject{
public ExpensiveObject(String value) {
System.out.println("Instance created: " + value);
}
}
Output:
Instance created: parameter1
Instance created: parameter2
You could work with a static Map from the parameters (here a simple string) to instances of ExpensiveObjectToCreate.
#RunWith(Parameterized.class)
public fnial class MyTestClass {
private static final Map<Parameter, ExpensiveObjectToCreate> MAPPING = new HashMap<>();
private ExpensiveObjectToCreate myEOTC;
public MyTestClass(String stringParameter) {
myEOTC = getEOTC(new Parameter(stringParameter));
}
private static getEOTC(Parameter parameter) {
ExpensiveObjectToCreate eotc = MAPPING.get(parameter);
if (eotc == null) {
eotc = new ExpensiveObjectToCreate(parameter.stringParameter);
MAPPING.put(parameter, eotc);
}
rturn eotc;
}
private static final class Parameter {
String stringParameter;
Parameter(String stringParameter) { this.stringParameter = stringParameter; }
#Override public int hashCode() { ... }
#Override public boolean equals(Object other) { ... }
}
}
However, if you also need to limit the number of expensive objects, you should do more work, for example a cache could be a solution.
If you're using Junit 4:
private static ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";
#BeforeClass
public static void setUpBeforeClass() throws Exception {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
If Junit 3:
private static ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";
#BeforeClass
protected static void setUpBeforeClass() throws Exception {
myObject = new ExpensiveObjectToCreate(stringParameter);
}
In both cases the object will be created once for all the unit tests.
Edit: The String I am not sure where it came from, so I am asuming that the String is the same for all unit tests.

Categories

Resources