Mockito: How to properly mock a List of Spring Services - spring

I have the following Spring Service class that I'm trying to test with Mockito:
#Service
public class ObjectExportService {
#Autowired
protected List<SecuredService<? extends SecuredObject>> securedServices;
public void doStuff() {
for(int i = 0; i < this.securedServices.size(); i++){
SecuredService<? extends SecuredObject> securedSrv = this.securedServices.get(i);
//this access works
}
for (SecuredService<? extends SecuredObject> securedSrv : this.securedServices) { //this access does not work
}
}
}
This is my Test class for that service:
#RunWith(MockitoJUnitRunner.class)
public class ObjectExportServiceTest {
#InjectMocks
private ObjectExportService objectExportService;
#Mock
protected List<SecuredService<? extends SecuredObject>> securedServices;
#Test
public void testDoStuff(){
objectExportService.doStuff();
Assert.assertTrue(true);
}
}
When I run the test, I get a NullpointerException, but only in the for-each loop.
First I assumed is a similar problem as described in this thread:
I have Mocked the List and would therefore need to mock the iterator() call.
The solutions provided in that thread didn't work for me, because I am actually autowiring a List.

So I stumbled across this solution in another thread. Simply changing the #Mock to #Spy resolved the issue for me:
#RunWith(MockitoJUnitRunner.class)
public class ObjectExportServiceTest {
#InjectMocks
private ObjectExportService objectExportService;
#Spy // <-- change here
protected List<SecuredService<? extends SecuredObject>> securedServices;
#Test
public void testDoStuff(){
objectExportService.doStuff();
Assert.assertTrue(true);
}
}

Related

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

autowired #components null in unit test

I have a class:
#Component
public class B {
#Autowired
private A a;
}
and A is a component:
#Component
public class A{}
In unit test class BTest:
public class BTest {
#Test
public void testBMethod() {
}
}
I am not using an xml to define context or for beans to be picked from.
What is the cleanest way I can get the test to run?
You don't have to use Spring for the unit tests. Mockito may be used for this.
public class BTest {
#Mock
private A a;
#Mock
private B b;
#Test
public void testBMethod() {
}
}
For more details, you may check https://springframework.guru/mocking-unit-tests-mockito/
and https://dzone.com/articles/use-mockito-mock-autowired

How to Pass #Value to a #Component for Spring Unit Testing

Im writing unit tests for services, controllers, etc however theres is a #Component that has the following values
#Component
Public class myclass
#Autowired
Private MyTemplate myTemplate
#Value("$someString")
Private String someString
#PostConstruct
Public void loadString()
...
How would I manually load values into the #Values? I have tried with Mocks, TestPropertySource, ReflectionTestUtils, among other ways found around
You can inject the #Value in test class by ReflectionTestUtils. Load container only in case of Controllers. For writing test cases for services and dao you don't need to load the spring container.
public class TestClass{
private #InjectsMock ServiceClass service;
#BeforeAll
public void setUp(){
ReflectionTestUtils.setField(service, "someString", "someValue");
}
//your test cases over here.
}
I can immediately think of two options
1) You could define $someString in your test/resources/test.properties
#RunWith(SpringRunner.class)
#TestPropertySource(locations="classpath:test.properties")
public class ClassTest {
}
2) do it manually
#RunWith(SpringRunner.class)
public class ClassTest {
#Autowired
private MyClass miclass;
#Before
public void setupObject() {
miclass.setProperty("someting");
}
}

Mock an object which is part of mocked object

when I run the test case I get AnObj mocked. this is used from inside the target classes method. when that method gets invoked the 'anOtherObj' is accessed and that is found to be null. Can some one please point out how to make sure 'anOtherObj' is not null so that I dont get nullpointer there?
#Test
public class TestTargetTest {
#Mock
private AnObj anObj;
#InjectMocks
private TestTarget testTarget;
#BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testTarget() {
when(anObj.someMethod()).thenCallRealMethod();
testTarget.testTarget();
}
}
#Component
public class TestTarget {
#Autowired
private AnObj anObj;
public void testTarget(){
anObj.someMethod();
}
}
#Component
public class AnObj {
#Autowired
private AnOtherObj anOtherObj;
public void someMethod(){
syso(anOtherObj.toString());
}
}
You need to initialize annotated mocks in your test class.
#BeforeMethod
public void beforeClass() {
MockitoAnnotations.initMocks(this);
}
Why would you care what's inside mock (AnObj)? I assume you haven't yet declared interactions on that mock using Mockito.when.
As mentioned by #Valya that point was valid. I shouldn't have mocked that. I needed to autowire 'AnObj'. Thanks a lot for all the help. It made the difference.

Mockito - Accessing private/autowired fields for verify()

So I am new to Mockito for testing facades. So basically I want to check, if a method of Service gets called once.
Here would be a simplified example
My Service
public class Service {
public int myMethod(int index, int number) {
if (index<4){
index = index + number;
}
return index;
}
}
My Facade:
public class Facade {
private Service service;
public void method(){
int i = service.myMethod(4, 2);
}
}
and finally my Test:
public class FacadeTest {
#InjectMocks
private Facade classUnderTest;
#Mock (name="service")
private Service service;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void test(){
verify(classUnderTest, times(1)).service.myMethod(4,2);
}
}
I know it is possible to use Getter/Setter-methods in my Facade to return the Service, but I want to do it, without doing that.
Is it possible, in the way I want to, without doing any change to the Facade?
And is there a difference, when I have a Spring-project and used #Autowired for the service variable inside the Facade?
Thanks!
Using #InjectMocks will inject your annotated #Mock service in your facade.
So you don't need any getter or setter for your test.
It seems you forgot to call method in your test.
Try with this :
#Test
public void test(){
classUnderTest.method();
verify(service, times(1)).service.myMethod(4,2);
}
Using #Autowired service in your facade will have no impact on your test since spring is not used in it. Spring will inject the right bean when you'll run your application.

Resources