How do I mock both a final and a static using Mockito - mockito

So I have a couple Tests that run using mockito. One requires a static to be mocked so I use PowerMockito like this...
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
Next I have another test that mocks a final class like this...
HttpSecurity security = Mockito.mock(HttpSecurity.class);
The second one doesn't work at first, I get the following failure....
Cannot mock/spy class org.springframework.security.config.annotation.web.builders.HttpSecurity
Mockito cannot mock/spy because :
- final class
So I looked and found this question which suggests adding the file .../src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with mock-maker-inline
But when I add that the first line fails with...
org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class java.lang.Class
How do I get both to work?
Update
I didn't want to clutter up the question with the entire test which really doesn't provide any extra context. However, since people are insisting and seem to misunderstand the question...
// Static
#ExtendWith(MockitoExtension.class)
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebClient.class)
public class RasaServiceTest {
#Mock
private WebClient webClientMock;
#Mock
private WebClient.RequestHeadersSpec requestHeadersMock;
#Mock
private WebClient.RequestHeadersUriSpec requestHeadersUriMock;
#Mock
private WebClient.RequestBodyUriSpec requestBodyUriMock;
#Mock
private WebClient.ResponseSpec responseMock;
private MyService service = new MyService();
#BeforeAll
public void setup(){
PowerMockito.mockStatic(WebClient.class);
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
}
#Test
public void HappyPath(){
MessageResponseItem item = new MessageResponseItem();
item.setRecipientId("id");
item.setResponseText("response");
MessageResponseItem[] items = {item};
when(webClientMock.post()).thenReturn(requestBodyUriMock);
when(requestHeadersUriMock.uri("/webhooks/rest/webhook")).thenReturn(requestHeadersMock);
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
when(responseMock.bodyToMono(MessageResponseItem[].class)).thenReturn(Mono.just(items));
InferenceEngineRequest request = new InferenceEngineRequest();
MessageResponseItem[] result = service.call(request).block();
assertThat(result.length).isEqualTo(1);
assertThat(result[0].getResponseText()).isEqualTo("response");
}
}
// Final
#RunWith(MockitoJUnitRunner.class)
public class RemoveMeConfigTest {
#Test
public void happyPath() throws Exception {
HttpSecurity security = Mockito.mock(HttpSecurity.class);
CsrfConfigurer<HttpSecurity> csrf = Mockito.mock(CsrfConfigurer.class);
RemoveMeConfig config = new RemoveMeConfig();
Mockito.when(
security.csrf()
).thenReturn(csrf);
Mockito.when(
csrf.disable()
).thenReturn(security);
config.configure(security);
Mockito.verify(
security,
Mockito.times(
1
)
).csrf();
Mockito.verify(
csrf,
Mockito.times(1)
).disable();
}
}

Related

repository always null after initilization of testing containers

I am attempting to use TestingContainers. I was able to get it to run but my tests are always null. I am trying to avoid mocking but rather having real data.
Repository
#Sql("classpath:data.sql")
class OrderDataRepositoryTest extends AbstractTestConfiguration {
//#Mock
#MockBean
//#Autowired
private OrderDataRepository orderRepository;
private AutoCloseable closeable;
#BeforeEach
public void init() {
closeable = MockitoAnnotations.openMocks(this);
}
#AfterEach
void closeService() throws Exception {
closeable.close();
}
#Test
void getAllUsersTest() {
List<Order> orders = orderRepository.findAll();
orders.toString();
}
}
config
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#Testcontainers
public abstract class AbstractTestConfiguration {
#Container
private MySQLContainer database = new MySQLContainer("mysql:8.0");
#Test
public void test() {
assertTrue(database.isRunning());
}
}
main
#SpringBootTest
#Sql("classpath:init.sql")
#TestPropertySource("classpath:application-test.yml")
class TentingContainerApplicationTests {
}
application.properties
spring:
application:
datasource:
url: jdbc:mysql:8.0:///test?TC_INITSCRIPT=file:src/main/resources/init.sql
driver-class-name: com.mysql.jdbc.Driver
The commented out
//#Mock
#MockBean
//#Autowired
is what I tried. Of course mock works out but I want real data for the #services and #repository classes.
advice?
If you want to test your database-related code in isolation (I assume you're using Spring Data JPA) then #DataJpaTest fits perfectly.
This annotation will create a sliced Spring context for you that contains only persistence relevant beans like: DataSource, EntityManager, YourRepository. This doesn't include your service classes, your #Component classes, or #RestController.
By default, this annotation tries to configure an embedded in-memory database as the DataSource. We can override this (and you already did with some of your code examples) behavior to use Testcontainers:
#DataJpaTest
#Testcontainers
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class OrderDataRepositoryTest {
#Container
static MySQLContainer database = new MySQLContainer("mysql:8.0");
#DynamicPropertySource
static void setDatasourceProperties(DynamicPropertyRegistry propertyRegistry) {
propertyRegistry.add("spring.datasource.url", database::getJdbcUrl);
propertyRegistry.add("spring.datasource.password", database::getPassword);
propertyRegistry.add("spring.datasource.username", database::getUsername);
}
#Autowired
private OrderDataRepository orderRepository;
#Test
void shouldReturnOrders() {
}
}
If you want to write another test that includes all your beans and also starts the embedded servlet container, take a look at #SpringBootTest for writing integration tests.
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#Testcontainers
class MyIntegrationTest {
#Container
static MySQLContainer database = new MySQLContainer("mysql:8.0");
#DynamicPropertySource
static void setDatasourceProperties(DynamicPropertyRegistry propertyRegistry) {
propertyRegistry.add("spring.datasource.url", database::getJdbcUrl);
propertyRegistry.add("spring.datasource.password", database::getPassword);
propertyRegistry.add("spring.datasource.username", database::getUsername);
}
#Autowired
private ServiceA serviceA;
#Autowired
private OrderDataRepository orderDataRepository;
}
When working with a Spring TestContext for your test and Mockito, make sure to understand the difference between #Mock and #MockBean.

Mockito: How to test a class's void method?

Unit test noob here.
I have three classes: Db1Dao, Db2Dao, ExecuteClass where Db1Dao, Db2Dao are database access objects for two different databases. My goal is to fetch some data from db1 using Db1Dao and run executeClass.execute() to "put" the processed data into db2 using Db2Dao.
My ExecuteClass looks like this:
class ExecuteClass {
private Db1Dao db1Dao;
private Db2Dao db2Dao;
public void execute() {
...
List<String> listOfString = getExternalData(someParam);
List<Metadata> metadatum = db1Dao.get(someInputs);
... I do something to generate a list of new class `A` based on listOfString & metadatum ...
try {
db2Dao.put(listOfA);
} catch (PutException e){
...
}
}
public List<String> getExternalData(SomeClass someParam){
... do something
return listOfString;
}
}
Now I want to test:
Given a specific listOfString (returned by getExternalData) and a specific metadatum (returned by db1Dao.get):
Will I get the desired listOfA?
Am I able to call db2Dao.put and its input parameter is listOfA?
Particularly, I have hard-coded sample listOfString and metadatum and desired listOfA (and they will be passed via an object MockData, see the following code) but I don't know how to write the test using Mockito. The following is a test class I wrote but it does not work:
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
// executeClass.execute(); not working neither...
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(listOfA);
}
}
Could anyone please let me know? Thank you in advance!!
You should not create a spy of the same class you want to test. Instead, try to write a unit test for the smallest amount of code (e.g. a public method) and mock every external operator (in your case Db1Dao and Db2Dao).
If testing a public method involves calling another public method of the same class, make sure to mock everything inside the other public method (in your case getExternalData). Otherwise, this other public method might be a good candidate for an extra class to have clear separation of concerns.
So, remove the ExecuteClass executeClassSpy = Mockito.spy(executeClass); and make sure you setup everything with Mockito what's called within getExternalData.
To now actually, verify that Db2Dao was called with the correct parameter, either use your current approach with verifying the payload. But here it's important to 100% create the same data structure you get while executing your application code.
Another solution would be to use Mockito's #Captor. This allows you to capture the value of why verifying the invocation of a mock. Later on, you can also write assertions on the captured value:
#Captor
private ArgumentCaptor<ClassOfListOfA> argumentCaptor;
#Test
public void yourTest() {
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals("StringValue", argumentCaptur.getValue().getWhateverGetterYouHave);
}
The following code worked for me.
I partially accepted #rieckpil's answer. I used #Captor which is very handy.
The reason I had to mock getExternalData() is because its implementation is still a "TODO".
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
#Captor
private ArgumentCaptor<List<A>> argumentCaptor;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals(listOfA, argumentCaptor.getValue());
}
}

Unable to mock functions in when running mockmvc test

I am writting test case of my controller using mockmvc
#Mock
private AService aService;
#InjectMocks
private AController aController;
#BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(aController)
.setCustomArgumentResolvers(putAuthenticationPrincipal) // for passing the authentication principal
.build();
}
now when i trying to test
#Test
public void testfunction() throws Exception {
String id = UUID.randomUUID().toString();
Mockito.when(aService.getAccount(Mockito.anyString())).thenThrow(new Exception("not avalible"));
mockMvc.perform(MockMvcRequestBuilders.get("/account/{id}", id)
....
}
In this the aService.getAccount() is not getting mock. that is why I am not getting the desired result..
I didn't understand why the mocking of function isn't working in this case.
In a #WebMvcTest, you should not create a mock of your controller. Spring needs to create a controller in it’s context, and inject collaborating services into it.
To do that:
annotate the test class with #WebMvcTest(YourController.class)
annotate collaborating services with #MockBean, not #Mock

How can I use multiple mocks of an interface for a Java EE "#Inject private Instance<T> implementations"?

I have an interface:
public interface Service {
void doService();
}
And a class:
public class ServiceUser {
#Inject
#Any
private Instance<Service> serviceImplementations;
public void work() {
serviceImplementations.forEach(service -> service.doService());
}
}
And a testcase:
public class ServiceUserTest {
#Mock
private Service firstImpl;
#Mock
private Service secondImpl;
#InjectMocks
private ServiceUser serviceUser;
#Test
public void testAllImplementationsCalled() {
serviceUser.work();
verify(firstImpl).doService();
verify(secondImpl).doService();
}
}
When I run the testcase, I get a NullPointerException in ServiceUser, where on debugging serviceImplementations is null. If I create two fields in ServiceUser I can get the two instances injected (both mocks are injected, I checked during debugging).
public class ServiceUser {
#Inject
#Any
private Instance<Service> serviceImplementations;
#EJB
private Service firstImpl;
#EJB
private Service secondImpl;
public void work() {
serviceImplementations.forEach(service -> service.doService());
}
}
How can I make this work?
Surprisingly, I couldn't find a good existing fake or test double for Instance<T>, as in Instance<Service> serviceInstance = TestingInstance.of(firstImpl, secondImpl);.
You might want to create one—not using Mockito, but rather as an actual implementation—and test and use it. The interface is relatively small, particularly if you just throw UnsupportedOperationException on the select methods, and then you'll have an implementation you can use in all of your test cases.
Because it's not a mock, you would need an alternative to #InjectMocks, though; given the fragility of #InjectMocks as dependencies change, this may not be a bad thing anyway.

Using Mockito for writing ATG test case

Does anyone have idea about writing unit test case for ATG using Mockito? I came across following discussions while goggling -
Automated unit tests for ATG development and
Using PowerMock to obtain the ATG Nucleus in testing results in NPE
But need a help in setting up Nucleus and other dependencies (DAS, DPS, DSS etc.) and a sample test class for droplet using Mockito.
We are using ATG Dust where we have to set all the dependencies. I am wondering if we can replace ATG Dust completely with Mockito. Here is the example how we are writing the test cases -
A Base class for setting Nucleus -
package com.ebiz.market.support;
import java.io.File;
import java.util.Arrays;
import atg.nucleus.NucleusTestUtils;
import atg.test.AtgDustCase;
import atg.test.util.FileUtil;
public class BaseTestCase extends AtgDustCase {
public atg.nucleus.Nucleus mNucleus = null;
private final String ATGHOME="C://ATG/ATG9.4//home";
private final String ATGHOMEPROPERTY = "atg.dynamo.home";
protected void setUp() throws Exception {
super.setUp();
String dynamoHome = System.getProperty(ATGHOMEPROPERTY);
if(dynamoHome == null)
System.setProperty(ATGHOMEPROPERTY, ATGHOME);
File configpath = NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
FileUtil.copyDirectory("src/test/resources/config/test/", configpath.getAbsolutePath(), Arrays.asList(new String [] {".svn"}));
copyConfigurationFiles(new String[]{"config"}, configpath.getAbsolutePath(), ".svn");
}
public File getConfigPath() {
return NucleusTestUtils.getConfigpath(this.getClass(), this.getClass().getName(), true);
}
}
Writing the test case by extending the base class -
public class BizDropletTest extends BaseTestCase {
private BizDroplet bizDroplet;
#Before
public void setUp() throws Exception {
super.setUp();
mNucleus = NucleusTestUtils.startNucleusWithModules(new String[] { "DSS", "DPS", "DAFEAR" }, this.getClass(),
this.getClass().getName(), "com/ebiz/market/support/droplet/BizDroplet");
autoSuggestDroplet = (AutoSuggestDroplet) mNucleus.resolveName("com/ebiz/market/support/droplet/BizDroplet");
try {
bizDroplet.doStartService();
} catch (ServiceException e) {
fail(e.getMessage());
}
}
/**
Other methods
*/
}
So, how Mockito can handle these? Again, for me the target is to replace ATG Dust with Mockito completely because ATG Dust take lot of time in running tests due to huge dependencies.
Thanks.
Using Mockito you don't setup Nucleus or other dependencies (unless you need it). You simply mock the objects that you need to use.
Consider a simple class ProductUrlDroplet that retrieves a product from the repository and then outputs a url based on this. The service method would look something like this:
public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse) throws ServletException, IOException {
Object product = pRequest.getObjectParameter(PRODUCT_ID);
RepositoryItem productItem = (RepositoryItem) product;
String generatedUrl = generateProductUrl(pRequest, productItem.getRepositoryId());
pRequest.setParameter(PRODUCT_URL_ID, generatedUrl);
pRequest.serviceParameter(OPARAM_OUTPUT, pRequest, pResponse);
}
private String generateProductUrl(DynamoHttpServletRequest request, String productId) {
HttpServletRequest originatingRequest = (HttpServletRequest) request.resolveName("/OriginatingRequest");
String contextroot = originatingRequest.getContextPath();
return contextroot + "/browse/product.jsp?productId=" + productId;
}
A simple test class for this will then be:
public class ProductUrlDropletTest {
#InjectMocks private ProductUrlDroplet testObj;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
#Mock private RepositoryItem productRepositoryItemMock;
#BeforeMethod(groups = { "unit" })
public void setup() throws Exception {
testObj = new ProductUrlDroplet();
MockitoAnnotations.initMocks(this);
Mockito.when(productRepositoryItemMock.getRepositoryId()).thenReturn("50302372");
}
#Test(groups = { "unit" })
public void testProductURL() throws Exception {
Mockito.when(requestMock.getObjectParameter(ProductUrlDroplet.PRODUCT_ID)).thenReturn(productRepositoryItemMock);
testObj.service(requestMock, responseMock);
ArgumentCaptor<String> argumentProductURL = ArgumentCaptor.forClass(String.class);
Mockito.verify(requestMock).setParameter(Matchers.eq(ProductUrlDroplet.PRODUCT_URL_ID), argumentProductURL.capture());
Assert.assertTrue(argumentProductURL.getValue().equals("/browse/product.jsp?productId=50302372"));
}
}
The key components are that you need to initialise the class you want to test (testObj). You then simply construct the response for each of the input parameters of the objects you are going to use (in this case productRepositoryItemMock represents the RepositoryItem and productRepositoryItemMock.getRepositoryId() returns a String that you can then test against later).
You will also notice that this test only validates the service method and not the individual methods. How you do it is up to you but generally I've been focused on testing my service and handleXXX methods in the formhandlers and droplets.
Testing the XXXManager, XXXUtil and XXXService classes will all have their own tests and should be 'mocked' into the droplets and formhandlers. For these I would write tests for each method though.
PowerMockito only really comes into the picture when you need to mock static methods and classes and the documentation does enough to explain that.

Resources