Inject an EJB into JUnit test class - java

I defined an EJB as follows:
#Stateless
#LocalBean
public class Foo {
#Inject
private Boo boo;
public void doSomething() {
boo.doOther();
}
}
And:
#Named
#RequestScope
public class Boo {
public void doOther() {
// I do, I do...
}
}
I would like to inject the Foo EJB into a JUnit test class:
import org.junit.*
public class FooTest {
#EJB
private Foo foo;
#Test
public void doSomethingTest() {
foo.doSomething();
assertTrue(true);
}
}
... But this code returns a NullPointerException.
What's wrong? How can I properly define that test by using Java EE CDI?

Related

Mocking Autowire in a class

I have an XYZ class which is autowired in ABC and in class MyClass I have a method name doSomething() inside that method I do ABC abc = new ABC(); Then I call abc.someMethod();
Please see code sample below :
Class ABC
public class ABC {
#Autowire
private XYZ xyz;
public void someMethod()
{
//Some stuff
xyz.someFunc();
}
}
Class MyCLass
public class MyCLass {
public void doSomething() {
ABC abc = new ABC();
abc.someMethod();
}
}
Need unit test doSomething() but I NPE as XYZ is null in ABC. How can I mock #Autowire in this case.
If you use constructor injection instead of field injection, you can create the mock and give it to the constructor of ABC:
public class ABC {
private final XYZ xyz;
public ABC(XYZ xyz) {
this.xyz = xyz;
}
public void someMethod()
{
//Some stuff
xyz.someFunc();
}
}
Then in your test, when you create the instance under test, you just create it and hand over the mock:
XYZ mock = mock(XYZ.class);
ABC underTest = new ABC(mock);
You can use the following testing capabilities in your test:
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
Provide a configuration and use it, for example:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyTest.MyTestConfiguration.class)
public class MyTest {
// xyz injected into ABC and MyTest for convenience.
#Autowired
private XYZ xyz;
#Test
public void myTest() {
// Some Stubbing...
when(xyz.trySomething()).thenReturn(true);
// Some verification.
new ABC().doSomething();
verify(xyz, times(1))
.trySomething();
}
// Note it is used in #ContextConfiguration
#Configuration
static class MyTestConfiguration {
#Bean
XYZ xyz() {
return mock(XYZ.class);
}
}
}
The documentation is a bit extensive, search for the mentioned annotations here https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#integration-testing

How to mock double autowired class

In the following case, can I test "MainServiceImpl"?
【What I want to do】
・Test target object is "MainServiceImpl".
・SubMainServiceImpl is used without mock.
・SubSubMainServiceImpl.subSubSayHello method is used with mock. 
You may say "double autowired class is not recommended to mock." I know, but I want to know the above test is technically possible.
//Test Target Object
#Service
public class MainServiceImpl implements MainService {
#Autowired
private SubMainService subMainService;
#Override
public String mainSayHello() {
return "MainSayHello. Also..." + subMainService.subSayHello();
}
}
//MainServiceImpl depends on this class.
#Service
public class SubMainServiceImpl implements SubMainService {
#Autowired
private SubSubMainService subSubMainService;
#Override
public String subSayHello() {
return "SubSayHello. Also..." + subSubMainService.subSubSayHello();
}
}
//SubSubServiceImpl depends on this class.
#Service
public class SubSubMainServiceImpl implements SubSubMainService {
#Override
public String subSubSayHello() {
return "SubSubSayHello";
}
}
As a side note, I can mock direct-autowired class.
How can I mock "double" autowired class?
//Direct(not double) autowired class is mocked.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MockMainServiceTest {
#InjectMocks
MainServiceImpl mainService;
#Mock
SubMainService subMainService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void SubMainService_Mocked(){
doReturn("SubMainService_Mocked").when(subMainService).subSayHello();
Assert.assertThat(mainService.mainSayHello() ,is("MainSayHello. Also...SubMainService_Mocked"));
}
}
Technology
SpringBoot 2.5.4
JUnit 4.2
Java 1.8

Spring AOP - #Before not executing

I'm trying to implement a simple Spring AOP (v4) example using #Before advice with an in-place pointcut expression, but the aspect method is not invoked. I have all the required dependencies(spring-aop, aopalliance, aspectweaver). What am I doing wrong?
package com.xyz;
public class TestClass {
#PostConstruct
public void init() {
test();
}
public void test() {
...
}
}
The aspect:
#Aspect
#Component
public class MyAspect{
#Before("execution(* com.xyz.TestClass.test())")
public void beforeTest() {
...
}
}
The reason why AOP isn't executed is because the TestClass.test() is not invoked in spring context but has simple / plain invocation from TestClass.init().
To test your setup modify it to something similar to below so that the TestClass.test() invocation is managed by spring
package com.xyz;
public class TestClass {
public void test() {
...
}
}
Inject the TestClass into another class say AnotherTestClass and invoke test method from there
package com.xyz;
public class AnotherTestClass {
#Autowired
private TestClass testClass;
public void anotherTest() {
testClass.test();
}
}

Inject Mocks for objects created by Factory classes

I have the following class:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
And the Test class:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
}
How could I inject an Apple instance as a mock in MyClass?
You have 3 possibilities to solve this:
Abstract factory: Instead of using a static method, use a concrete factory class:
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
In your test class, mock the factory:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private AppleFactory appleFactoryMock;
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}
PowerMock: Use PowerMock to create a mock of a static method. Look at my answer to a relevant question to see how it's done.
Testable class: Make the Apple creation wrapped in a protected method and create a test class that overrides it:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
#Override
public void createApple() {
return appleMock;
}
}
}
Of course, in your test class you should test TestableMyClass and not MyClass.
I'll tell you my opinion on each of the methods:
The abstract factory method is the best one - This is a clear design that hides the implementation details
The testable class - Is the second option which requires minimum changes
The PowerMock option is my least favorite - Instead of going for a better design, you ignore and hide your problem. But that's still a valid option.
In addition of the solution proposed by Avi, you can choose a fourth possibility:
Inject into Factory:
This is, for me, the best option when you already have code to refacrot. With this solution you don't have to change porduction code but only factory class and test.
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = apple;
}
}
Now you can use your static factory simply:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}

Mockit redefineMethod not working because of interface or generic abstract

I'm trying to figure out why Mockit is not working for the following code:
public class TestClass {
#Test
public void test() {
Mockit.redefineMethods(ExecuterClass.class, new Object() {
#SuppressWarnings("unused")
public SomeService getService() {
return new MockSomeServiceImpl();
}
});
// Code to run test
}
}
public abstract class ExecuterClass<T,U,V,W> {
// Other methods/variables
public SomeService getService() {
return someProvider.getService();
}
}
public interface SomeService {
// Some method definitions
}
public class MockSomeServiceImpl implements SomeService {
// Some method implementations
}
The error I get back is:
java.lang.IllegalAccessError: tried to access class TestClass from class ExecuterClass
Any ideas on how to fix this?? In the end, I would like the test to use the MockSomeServiceImpl methods rather than those in SomeService implementation.
SomeService was generated by a WSDL, so I don't have the implementation that someObject.getService() returns. So I can't do Mockit.redefineMethods(SomeServiceImpl.class, MockSomeServiceImpl.class)

Categories