Inject string into class using Guice for JUnit test - java

I have a situation where I need to test a function but the class has injected String value like this:
public class SomeClass{
#Inject
#Named("api")
private String api;
public Observable<String> get(String uuidData){
//do something with "api" variable
}
}
Now how do I inject this from my JUnit test case? I am also using Mockito but it's not allowing me to mock primitive types.

It looks like there are two options here:
Option 1: Set up injection in the #Before of your JUnit test
//test doubles
String testDoubleApi;
//system under test
SomeClass someClass;
#Before
public void setUp() throws Exception {
String testDoubleApi = "testDouble";
Injector injector = Guice.createInjector(new Module() {
#Override
protected void configure(Binder binder) {
binder.bind(String.class).annotatedWith(Names.named("api")).toInstance(testDouble);
}
});
injector.inject(someClass);
}
Option 2: Refactor your class to use constructor injection
public class SomeClass{
private String api;
#Inject
SomeClass(#Named("api") String api) {
this.api = api;
}
public Observable<String> get(String uuidData){
//do something with "api" variable
}
}
Now your #Before method will look like this:
//test doubles
String testDoubleApi;
//system under test
SomeClass someClass;
#Before
public void setUp() throws Exception {
String testDoubleApi = "testDouble";
someClass = new SomeClass(testDoubleApi);
}
Out of the two options, I would say the second is preferable. You can see it leads to much less boiler-plate and the class can be tested even without Guice.

Related

Writing a Junit test for a boolean method with no parameters

I have a class where I want to write a junit test for.
This method has no parameters, can this method accordingly?
public class classTobeTested {
#Self
SlingHttpServletRequest request;
static final String keyword = "hello";
public boolean isActive() {
boolean check;
String pathChecker;
pathChecker = (request.getRequestURL()).toString();
check= pathChecker.contains(keyword);
return check;
}
}
This would be the testing class i had in mind
#RunWith(MockitoJUnitRunner.class)
public class testclasstobetested {
#Test
public void TestclassTobeTested() throws Exception{
classTobeTested CTT = new classTobeTested();
assertFalse(CTT.isActive("hello how are you"));
}
}
I know my method does not take a parameter but has strings declared inside the method.
How can i use assertFalse correctly to test a non param method.
Using annotations and Junit4 you can do it like this:
#RunWith(MockitoJUnitRunner.class)
public class testclasstobetested {
#InjectMocks
private classTobeTested CTT;
#Mock
private SlingHttpServletRequest request;
#Test
public void TestclassTobeTested() throws Exception{
when(request.getRequestURL()).thenReturn(new StringBuffer("hello how are you"));
assertFalse(CTT.isActive());
}
}

Mocking constructor using PowerMockito doesn't work

I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.

Using PowerMock to write unit test, mocked method fails to invoke

I recently learn to use PowerMock to write unit tests for a class called Module which extends class Base. They look like this.
public class Base {
protected final static ServiceA serviceA;
protected final static ServiceB serviceB;
static {
serviceA = ServiceA.getInstance();
serviceB = ServiceB.getInstance();
}
}
public class Module extends Base {
public DataA methodA() {
return serviceA.getDataA();
}
public DataB methodB() {
return serviceB.getDataB();
}
}
My unit tests look like this:
#PowerMockIgnore("javax.management.*")
#RunWith(PowerMockRunner.class)
#PrepareForTest({Module.class, ServiceA.class, ServiceB.class})
public class ModuleTest {
private Module module;
#Mock
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(ServiceA.class);
PowerMockito.when(ServiceA.getInstance).thenReturn(serviceA);
PowerMockito.mockStatic(ServiceB.class);
PowerMockito.when(ServiceB.getInstance).thenReturn(serviceB);
module = new Module();
// I spy it because it has other methods I need to mock
module = PowerMockito.spy(module);
}
#Test
public void methodATest() {
DataA dataA = new DataA();
PowerMockito.when(serviceA.getDataA()).thenReturn(dataA);
DataA data = module.methodA();
assertEquals(dataA, data);
}
#Test
public void methodBTest() {
DataB dataB = new DataB();
PowerMockito.when(serviceB.getDataB()).thenReturn(dataB);
DataB data = module.methodB();
assertEquals(dataB, data);
}
}
Everything looks straightforward but when I run ModuleTest, the methodBTest() doesn't pass. It seems that PowerMockito.when(serviceB.getDataB()).thenReturn(dataB) doesn't work and makes the real serviceB.getDataB() method invoked. So assertEquals(dataB, data) throws org.junit.ComparisonFailure.
If I put the methodBTest() before methodATest(), the methodATest() doesn't pass. Same reason.
If I put PowerMockito.when(serviceA.getDataA()).thenReturn(dataA) and PowerMockito.when(serviceB.getDataB()).thenReturn(dataB) in the setup(), everything works perfectly.
This borders me all day. Is there anyone knowing why this is happening and how to resolve it? I need the mocking statement written in the respective test methods because I may change the returned values.
Here's a solution involving (almost) no changes
#PowerMockIgnore("javax.management.*")
#RunWith(PowerMockRunner.class)
#PrepareForTest({Module.class, ServiceA.class, ServiceB.class})
public class ModuleTest {
private Module module;
private static ServiceA serviceA = Mockito.mock(ServiceA.class);
private static ServiceB serviceB = Mockito.mock(ServiceB.class);
#BeforeClass
public static void oneTimeSetup() throws Exception {
PowerMockito.mockStatic(ServiceA.class);
PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);
PowerMockito.mockStatic(ServiceB.class);
PowerMockito.when(ServiceB.class, "getInstance").thenReturn(serviceB);
}
#Before
public void setup() throws Exception {
module = new Module();
// I spy it because it has other methods I need to mock
module = PowerMockito.spy(module);
}
#Test
public void methodATest() {
DataA dataA = new DataA();
Mockito.when(serviceA.getDataA()).thenReturn(dataA);
DataA data = module.methodA();
assertEquals(dataA, data);
}
#Test
public void methodBTest() {
DataB dataB = new DataB();
Mockito.when(serviceB.getDataB()).thenReturn(dataB);
DataB data = module.methodB();
assertEquals(dataB, data);
}
}
What was changed (and why):
In Base: serviceA and serviceB are changed to protected (Module can not access if private)
used "proper" (AFAIK) syntax for PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);
used a #BeforeClass and made serviceA and serviceB static to "bypass" static initialization in Base
Tested with Junit 4.12, PowerMockito 1.6.2.
Note: it's also possible to leverage #SuppressStaticInitializationFor to achieve the same goal:
#SuppressStaticInitializationFor(value = "so46196071.Base") // suppress the static in Base (note this is my package name)
#PowerMockIgnore("javax.management.*")
#RunWith(PowerMockRunner.class)
#PrepareForTest({Module.class, ServiceA.class, ServiceB.class})
public class ModuleBisTest {
private Module module;
#Mock
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#Before
public void setup() throws Exception {
// MockitoAnnotations.initMocks(this); /* this is not needed => done by the runner */
PowerMockito.mockStatic(ServiceA.class);
PowerMockito.when(ServiceA.class, "getInstance").thenReturn(serviceA);
PowerMockito.mockStatic(ServiceB.class);
PowerMockito.when(ServiceB.class, "getInstance").thenReturn(serviceB);
module = new Module();
Whitebox.setInternalState(Base.class, "serviceA", serviceA); // set serviceA in Base "by hand"
Whitebox.setInternalState(Base.class, "serviceB", serviceB); // set serviceB in Base "by hand"
// I spy it because it has other methods I need to mock
module = PowerMockito.spy(module);
}
// ...

Mockito - Impossible stubbing mocked object

I am newbie in Java world, but it is very hard understand why not can I stub method of a mocked object...
#RunWith(MockitoJUnitRunner.class)
public class ChildBLLIT extends BaseInteractorIT {
#InjectMocks
private ChildBLL ChildBLL = Mockito.mock(ChildBLL.class);
#Before
public void setUp() {
ChildBLL.engine = engineMock;
}
/**
* Test of getZipStatistics method, of class ChildBLL.
*/
#Test
public void testGetZipStatistics() {
final String testZipStatisticsText = "DummyZipStatistics";
//This method will throw the null pointer exception
when(ChildBLL.engine.getZIPStatistics()).thenReturn(testZipStatisticsText);
ChildBLL.getZipStatistics();
verify(ChildBLL.engine).getZIPStatistics();
}
}
When I try to stub the getZIPStatistics() method I get always a null pointer exception, of course I get, because in the getZIPStatistics() method there is an private object, which is not mocked... it seems to me the Mockito does not mocking the private fields... and unfortunately this is from another project:
public class BaseIT {
#Mock
protected static FromOtherProject engineMock;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}
Here I mocked the engine variable, but then how can I mock/stub the getZIPStatistics() method? This is this method:
public class FromOtherProject {
//...
public final String getZIPStatistics() {
return ZIPStatistics.toString();
}
}
What can I do?
Let's assume a simple class...
public class Account {
public String getPassword() {
return "abc";
}
}
...and simple class that contains it...
public class AccountHolder {
private Account account;
public String getAccountPassword() {
return this.account.getPassword();
}
}
So now we have a simple base class for all Account based tests...
public class AccountBasedTest {
#Mock
protected Account account;
}
...and a class that actually tests the AccountHolder...
#RunWith(MockitoJUnitRunner.class)
public class AccountHolderTest extends AccountBasedTest {
#InjectMocks
private AccountHolder accountHolder;
#Test
public void getAccountPasswort_must_return_account_password() {
Mockito.when( this.account.getPassword() ).thenReturn ("xyz");
Assert.assertEquals("xyz", this.accountHolder.getAccountPassword());
}
}
And that's all. The #InjectMocks, etc. annotations will also look in the superclasses, so you get your mocked account and that account will be put into your AccountHolder. No need to call MockitoAnnotations.initMocks. It shouldn't hurt, but it's not needed because you are using the MockitoJUnitRunner already, which does exactly that.

java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")

I'm using EasyMock(version 2.4) and TestNG for writing UnitTest.
I have a following scenario and I cannot change the way class hierarchy is defined.
I'm testing ClassB which is extending ClassA.
ClassB look like this
public class ClassB extends ClassA {
public ClassB()
{
super("title");
}
#Override
public String getDisplayName()
{
return ClientMessages.getMessages("ClassB.title");
}
}
ClassA code
public abstract class ClassA {
private String title;
public ClassA(String title)
{
this.title = ClientMessages.getMessages(title);
}
public String getDisplayName()
{
return this.title;
}
}
ClientMessages class code
public class ClientMessages {
private static MessageResourse messageResourse;
public ClientMessages(MessageResourse messageResourse)
{
this.messageResourse = messageResourse;
}
public static String getMessages(String code)
{
return messageResourse.getMessage(code);
}
}
MessageResourse Class code
public class MessageResourse {
public String getMessage(String code)
{
return code;
}
}
Testing ClassB
import static org.easymock.classextension.EasyMock.createMock;
import org.easymock.classextension.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ClassBTest
{
private MessageResourse mockMessageResourse = createMock(MessageResourse.class);
private ClassB classToTest;
private ClientMessages clientMessages;
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.replay(mockMessageResourse);
}
}
When I'm running this this test I'm getting following exception:
java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")
While debugging what I found is, it's not considering the mock method call
mockMessageResourse.getMessage("ClassB.title") as it has been called from the construtor (ClassB object creation).
Can any one please help me how to test in this case.
Thanks.
You need to call EasyMock.replay(mock) before calling the method under test. After calling the method under test you can call EasyMock.verify(mock) to verify the mock is called.
Next you need to add another expect call with the "title" argument since you call it twice.
Code:
EasyMock.expect(mockMessageResourse.getMessage("title")).andReturn("title");
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.verify(mockMessageResourse);
In my case, it was caused by the omission of a return value specification (andReturn(...)).
http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html for more details.
This can have various causes (someMock is the name of your mocked Object in this answer).
On the one side it can be that you need to expect the call via
expect(someMock.someMethod(anyObject()).andReturn("some-object");
like in Reda's answer.
It can also be that you forgot to call replay(someMock) before you used the mock, like you can see in Julien Rentrop's answer.
A last thing that is possible that wasn't mentioned here is that you used the mock somewhere else before in a test and forgot to reset the mock via reset(someMock).
This can happen if you have multiple Unit Tests like this:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
This will fail on one test with the IllegalStateException, because the mock a was not reset before being used in the next test. To solve it you can do the following:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#After
public void tearDown() throws Exception {
reset(a); // reset the mock after each test
}
You should put your call to replay after the expect calls, and before you use your mock. In this case you should change your test to something like this:
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
}
For me, this exception was occurring because the method I was trying to stub was final (something I hadn't realized).
If you want to stub a final method you'll need to use Powermock.

Categories