I have an abstract service class which autowires a specified type of repository.
abstract class SomeService<T extends SomeRepository<U>, U ...> {
#Autowrired
#Accessors(fluent = true)
#Getter(PROTECTED)
private U repositoryInstance;
}
Now I'm trying to create an abstract test class for subclasses of the service class.
#SpringBootTest
abstract class SomeServiceTest<T extends SomeService<U>, U extends SomeRepository<V>, V ...> {
#Autowrired
#Accessors(fluent = true)
#Getter(PROTECTED)
private T serviceInstance;
// DOES NOT WORK!
#MockBean
#Accessors(fluent = true)
#Getter(PROTECTED)
private U repositoryInstance; // != serviceInstance.repositoryInstance();
}
But mocking the bean in a test class of actual service class works.
class OtherServiceTest
extends SomeServiceTest<OtherService, OtherRepository, ...> {
#TestConfiguration
OtherServiceTestConfiguration {
// WORKS!!!
// == serviceInstance().repositoryInstance();
#MockBean private OtherRepository repositoryInstance;
}
}
class AnotherServiceTest
extends SomeServiceTest<AnotherService, AnotherRepository, ...> {
// WORKS!!!
// == serviceInstance().repositoryInstance();
#MockBean private AnotherRepository repositoryInstance;
}
How can I mock the SomeServiceTest#repositoryInstance so that it refers the same object as SomeServiceTest#serviceInstance.repositoryInstance()?
I don't know what is #Autowire, because I use #Autowired. But, as far I know, use autowire in the object declaration is a bad practice.
Instead of:
#Autowired
MyObject myObject;
Use it in the constructor:
Repository repository;
#Autowired
public SomeService(Repository repository) {
this.repository = repository;
}
And, in your test:
class SomeServiceTest {
#Mock
private Repository repositoryMock;
private Service serviceUnderTest;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
serviceUnderTest = new Service(repositoryMock);
}
You can always declare a default and an all-args constructor. The DI framework will instantiate via the first one, injecting the autowired fields, whereas you can instantiate with the all-args one from your test class, passing mock objects as constructor arguments.
Related
I'm using mokito to inject a mock. This object extends a class that requires a contructor with arguments. How to mock this object that requires constructor arguments and pass this arguments as mock too?
Example class
public abstract class AbstractClassRequireContructor{
protected AbstractClassRequireContructor(Object param) {
}
public class ClassA extends AbstractClassRequireContructor{
public ClassA(Object param) {
super(param); // required by super class
}
}
Test class
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA; // requires contructor from super class
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
// how to inject mocked argument?
classA = new ClassA(paramMockToBeAddedByConstructor); // this doesn't work
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue); // use injectMock class normally
}
}
Is there any another strategy to work arroung this better?
Drop the instantiation of a new ClassA object. It should work without it as follows:
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA;
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue);
}
}
I'm trying to inject a mock for a unit test but I keep getting a null point exception.
The class I'm trying to test is below, the null pointer seems to be with the ParameterFacade.
When I run the test it doesn't seem to be injecting the mock as the ParameterFacade is null.
#Service
public class PostUnderwriterTransactionProcessProvider extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
#Autowired
private ParameterFacade parameterService;
#Override
public Page startProcess(PostUnderwriterTransactionInput processInput) {
final PostUnderwriterTransactionContext context = new PostUnderwriterTransactionContext(processInput.getPolicy(),
setupStrataContextModel(POST_TRANSACTIONS),
processInput.getTransactionsTypes(),
processInput.getParameterSelectionCriteria(),
parameterService.shouldApplyCommissionFromPolicy());
context.setPostingFromInput(processInput.getAccount().getBalance(),
processInput.getAccount().getID(),
getBranch(),
processInput.getPolicy(),
processInput.getProcess(),
null);
return new AdhocTransactionPostingPage(new TransactionPostingContextModel(context));
}
}
The test is
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider();
policy = PolicyTestDataBuilder.aPolicy().build();
account = createAccount();
testSubject.setUserInfoProvider(MockUserInfoPartyProvider.getMockUserInfoProvider());
testSubject.setSystemPartyFacade(MockUserInfoPartyProvider.getMockSystemPartyFacade());
testSubject.setCodeModelFacade(codeModelFacade);
}
#Test
public void startProcessShouldCreateAdhocTransactionPostingPage() {
// Given
when(mockParameterService.shouldApplyCommissionFromPolicy()).thenReturn(true);
final ParameterSelectionCriteriaModel pscm = new ParameterSelectionCriteriaModel();
final List<TransactionTypeModel> transactions = createTransactionsTypes();
final PostUnderwriterTransactionInput input = new PostUnderwriterTransactionInput(policy, account, pscm, transactions);
// When
final Page page = testSubject.startProcess(input);
// Then
assertThat(page, instanceOf(AdhocTransactionPostingPage.class));
assertThat("Page Default Model is: ", page.getDefaultModelObject(), instanceOf(PostUnderwriterTransactionContext.class));
assertPageContextValues(page);
}
}
1. ParameterFacade is a spring container managed bean (as it is annotated with #Service and other spring annotations like #Autowired).
2. #RunWith is configured to use MockitoJUnitRunner which cannot instantiate spring managed container beans
Hence, in order to handle bean lifecycle in unit tests you'll need to
1. Use #RunWith(SpringJUnit4ClassRunner.class)
2. Annotate PostUnderwriterTransactionProcessProvider with #Autowired.
3. Change #Mock to #MockBean on ParameterFacade (org.springframework.boot.test.mock.mockito.MockBean)
Take a look at you following code, let's see what each line does -
#Mock
private ParameterFacade mockParameterService; //1
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject; // 2
#Before
public void setup() {
testSubject = new PostUnderwriterTransactionProcessProvider(); //3
}
Line 1 uses spring framework's #Mock annotation. This tells spring to mock an object of type ParameterFacade, create a mocked instance and hold it in the mockParameterService variable
Line 2 uses the #InjectMocks annotation, which tell spring to use the mocked object created in this test (which we created in line 1) and use it as a dependency in the variable testSubject when creating it. This will result in testSubject containing an instance of PostUnderwriterTransactionProcessProvider that has a dependency of a mocked type ParameterFacade injected to him
Line 3 creates a new instance of PostUnderwriterTransactionProcessProvider. this is pure java, no spring, no mocks, no dependencies. Simply create a new instance of that type the regular way java would do that. The instance that was created in 2 is replaced by this new plain instance and , in a way any assertion will override a previous value, which leaves the variable testSubject holding this object
The line
testSubject = new PostUnderwriterTransactionProcessProvider();
is overriding the instance created with
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
Remove the manual initialization to let the framework behave as designed.
Otherwise, if you want to be able to manually inject the dependency then consider refactoring the class to follow Explicit Dependency Principle
#Service
public class PostUnderwriterTransactionProcessProvider
extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
private final ParameterFacade parameterService;
#Autowired
public PostUnderwriterTransactionProcessProvider(ParameterFacade parameterService) {
this.parameterService = parameterService;
}
//...omitted for brevity
}
This can allow more flexibility when creating the subject
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider(mockParameterService);
//...omitted for brevity
I am having one #Inject object which i need to mock its throwing NPE while using #InjectMocks at my test class
Below is the structure of my class
Class ChildClass extends ParentClass
{
public myMethod(){
String myval=callParentClassMethod();
}
Class ParentClass{
#Inject
private MyService myservice;
//there is no constructor or setter method for this injected object
protected String callParentClassMethod(){
retrun myservice.getStringval();
}
}
Can you please suggest how to mock this MyService object.I have used #Mock and #Injected mock but its not working getting NPE. i tried to inject in both Base class and parent class but no luck.
following works for me:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#InjectMocks
private ChildClass childClass = new ChildClass();
#Mock
private MyService service;
#Test
public void test1() {
childClass.myMethod();
}
}
UPDATE
I've uploaded example project with test to https://github.com/shurick-k/mock-test
You've not specified exactly what type of #Inject annotation is used, so I assumed it is from javaee-api. Actually it does not matter.
I have to create a instance of a class, that have autowired elements, for test.
public class MyClass extends SomeOtherClass {
#Autowired
public MyClass(OtherClass1 one, OtherClass2 two){
super(one, two)
}
}
How can i in code create instance of this class, with the arguments wired in though spring?
Your test can be made Spring-aware if you use the SpringJUnit4ClassRunner to read in your Spring Context to be used in the test. For instance:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"the-config.xml"})
public final class MyClassTests {
#Autowired
private MyClass testee;
#Test
public void testSomething() {
assertThat(testee).doesSomethingExpected();
}
}
Note that you should reuse as much of your production config as possible and not create a parallel Spring Context config that mirrors it.
Instead of passing the other elements in as constructor arguments, you Autowire them as properties. Spring will then inject the objects.
public class MyClass extends SomeOtherClass {
#Autowired
private OtherClass1 one;
#Autowired
private OtherClass2 two
public MyClass(){
super(one, two)
}
}
Edit: Based on http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/, adding #Autowired to the constructor is also valid.
If you want to Autowire MyClass, you must annotate it with #Component or a similar annotation such as #Service.
#Component
public class MyClass extends SomeOtherClass
Then, you can use it in other classes
public class ClassThatUsesMyClass {
#Autowire
private MyClass myClass;
}
I am mocking an abstract class like below:
myAbstractClass = Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS);
the problem is that MyAbstractClass has some dependencies injected via EJB annotations and there are not setters. Is there a way to inject the dependencies?
#InjectMocks does not work with Abstract classes.
I am using junit5 for this.
What I did is instantiate the abstract class with a new abstractClass() in #BeforeEach and call the methods by super if the method is not abstract(using this because I have protected methods), after this I use ReflectionUtils.setField() to set the mocks in the abstract class and test every method and works pretty well. I leave a simple example that works.
AbstractClass
public abstract class AbstractClass {
#Autowired
private Environment environment;
protected String getProperty(String property){
return environment.getRequiredProperty(property);
}
}
AbstractClassTest
#ExtendWith(MockitoExtension.class)
class AbstractClassTest {
AbstractClass abstractClass;
#Mock
Environment environment;
#BeforeEach
void setUp() {
abstractClass = new AbstractClass() {
#Override
public String getProperty(String property) {
return super.getProperty(property);
}
};
ReflectionTestUtils.setField(abstractClass, "environment", environment);
}
#Test
void shouldReturnProperty() {
String propertyValue = "this property";
when(environment.getRequiredProperty("property")).thenReturn(propertyValue);
String property = abstractClass.getProperty("property");
assertEquals(propertyValue, property);
}
}
This is just using mockito and junit5 to test.
Remember to call ReflectionUtils after you instantiate the class with new AbstractClass() or the mocks won't be injected.
Any improve on this implementation is welcome :D.
Since you cannot instantiate an Abstract class there is nothing to test. I would recommend that you create child class (it could be a nested class inside your test class), and then run your tests that way. Then you can use the #Mock, #InjectMocks as you would normally.
You can use the Powermock library to inject mocks in myAbstractClass using Whitebox.setInternalState(myAbstractClass, mock(MockedClass.class));
Junit 4 specific solution
Abstract class that need to be tested
#Slf4j
public abstract class AdhocNotificationEmail {
#Autowired
protected CustomerNotificationRepository customerNotificationRepository;
protected abstract Map<String, String> abstractMethod(AdhocNotificationDTO adhocNotificationDTO);
public JSONObject concreteMethod(){
// some stuff that needs to be tested and common to all subclasses
}
}
Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
public class AdhocNotificationEmailTest{
#Mock
protected CustomerNotificationRepository customerNotificationRepository;
private AdhocNotificationEmail unit;
#Before
public void setUp() {
unit = new AdhocNotificationEmail() {
#Override
protected Map<String, String> abstractMethod(AdhocNotificationDTO notificationDTO) {
return null;
}
};
unit.customerNotificationRepository = customerNotificationRepository;
}
#Test
public void concreteMethod_greenPath() {
final String templateName = "NOTIFICATION_TEMPLATE";
final AdhocNotificationDTO adhocNotificationDTOStub = getAdhocNotificationDTOStub(templateName);
final CustomerNotification customerNotificationStub = getCustomerNotificationStub(templateName);
when(customerNotificationRepository.findByIdAndTemplateName(id, templateName)).thenReturn(customerNotificationStub);
final JSONObject response = unit.concreteMethod(adhocNotificationDTOStub);
assertNotNull(response);
}
Personally, what I like to do is to extend the abstract with an anonymous class declared in the #Before (or #BeforeEach in junit.jupiter). This way I can achieve the following:
Don't mock the class that I want to test (like you are doing with Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS)), since that is kind of an anti-pattern. You only want to Mock the dependencies of the class you are testing;
You can provide Mocks for the dependencies of the abstract class, and that are called by non-abstract methods;
You can test non-abstract methods that call abstract methods
Example:
class TestAbstractClass {
#Mock
private ServiceDependency dependency;
private AbstractClass abstractClass;
#BeforeEach
void setUp() {
abstractClass= new AbstractClass (dependency) { };
}
#Test
void test(){
Mockito.when(dependency.someMethod()).thenReturn(something);
var result = abstractclass.someNonAbstractMethod();
// assertions
}
}
Good practice is to write unit tests for all possible classes which inherits from this abstract class. Because in theory it is possible situation. This dependency should be mocked and you should forget about mocking dependencies of this EJB component.
Maybe some code snippets would help to clarify what you try to achieve here.