android, how to use mockk to mock BuildConfig.DEBUG - mockk

using mockk for unit test, and would like to mock the BuilConfig.DEBUG.
io.mockk.mockkObject(BuildConfig::class) // or mockkStatic
io.mockk.every { BuildConfig.DEBUG } returns true //<=== throws
but it throws exception
Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
How to mock the BuildConfig.DEBUG using mockk?

Related

thenThrow() not throwing an exception

I have a method in OneServiceImpl class as follows. In that class I am calling an interface method from another class.
public class OneServiceImpl {
//created dependency
final private SecondService secondService;
public void sendMessage(){
secondService.validateAndSend(5)
}
}
public interface SecondService() {
public Status validateAndSend(int length);
}
public class SecondServiceImpl {
#Override
public Status ValidateAndSend(int length) {
if(length < 5) {
  throw new BadRequestException("error", "error");
}
}
}
Now when I am try to perform unit test on OneServiceImpl I am not able to throw a BadRequestException.
when(secondService.validateAndSend(6)).thenThrow(BadRequestException.class);
Not quite sure what your use case is, but I think you should write an own test to accept and test an exception.
#Test(expected = BadRequestException.class)
public void testValidateAndSend(){
SecondService secondService = new SecondService();
secondservice.ValidateAndSend(6); //method should be lowercase
}
Not sure this is the case considering you didn't post a full example of code + unit tests, but your mock will throw only when you are passing 6 as parameter. When configuring the behaviour of your mock with when you are telling it to throw only when the validateAndSend method is called with parameter 6.
when(secondService.validateAndSend(6)).thenThrow(...)
In your code you have 5 hardcoded. So that mock will never throw for the code you have, because it's configured to react to an invocation with parameter 6 but the actual code is always invoking it passing 5.
public void sendMessage(){
secondService.validateAndSend(5)
}
If the value passed to the mock is not important you could do something like the following, that will throw no matter what's passed to it:
when(secondService.validateAndSend(any())).thenThrow(BadRequestException.class);
On the other hand, if the value is important and it has to be 5 you could change the configuration of your mock with:
when(secondService.validateAndSend(5)).thenThrow(BadRequestException.class)

How to throw exception from Spring AOP declarative retry methods?

I'm implementing some retry handling in my methods using Spring Retry.
I have a Data Access Layer (DAL) in my application and a Service Layer in my application.
My Service layer calls the DAL to make a remote connection to retrieve information. If the DAL fails it will retry. However, if the number of retries fails I would like to rethrow an exception.
In my current project I something very similar to this:
#Configuration
#EnableRetry
public class Application {
#Bean
public Service service() {
return new Service();
}
}
#Service
class Service {
#Autowired
DataAccessLayer dal;
public void doSomethingWithFoo() {
Foo foo = dal.getFoo()
// do something with Foo
}
}
#Service
class DataAccessLayer {
#Retryable(RemoteAccessException.class)
public Foo getFoo() {
// call remote HTTP service to get Foo
}
#Recover
public Foo recover(RemoteAccessException e) {
// log the error?
// how to rethrow such that DataAccessLayer.getFoo() shows it throws an exception as well?
}
}
My Application has a Service and the Service calls DataAccessLayer getFoo. If getFoo fails a number of times the DAL will handle the retries. If it fail's after that I'd like my Service layer to do something about it. However I'm not sure how to let that be known. I'm using intelliJ and when I try to throw e; in the #Recover recover method I don't get any warnings that DataAccessLayer.getFoo throws any exceptions. I'm not sure if it will. But I'd like the IDE to warn me that when the retries fail a new exception will be thrown to let the Service layer know to expect it. Otherwise if it calls dal.getFoo it doesn't know to handle any errors. How is this typically handled? Should I not use the AOP declarative style and go for imperative?
You can change getFoo() (and recover()) to add throws <some checked exception> and wrap the RemoteAccessException in it (in recover()).
That will force the service layer to catch that exception.

Mockito MockedStatic when() "Cannot resolve method"

I am trying to use Mockito MockedStatic to mock a static method.
I am using mockito-core and mockito-inline version 3.6.0 with Spring Boot and maven.
I can't manage to make the mock work, I have a "Cannot resolve method post" on the Unirest::post that you can see in the code below:
#Test
public void test() {
try (MockedStatic<Unirest> mock = Mockito.mockStatic(Unirest.class)) {
mock.when(Unirest::post).thenReturn(new HttpRequestWithBody(HttpMethod.POST, "url"));
}
}
The Unirest class comes from the unirest-java package.
Did someone encounter this issue already and have a solution?
The method Unirest.post(String url) takes an argument and hence you can't refer to it using Unirest::post.
You can use the following:
#Test
void testRequest() {
try (MockedStatic<Unirest> mockedStatic = Mockito.mockStatic(Unirest.class)) {
mockedStatic.when(() -> Unirest.post(ArgumentMatchers.anyString())).thenReturn(...);
someService.doRequest();
}
}
But keep in mind that you have to mock now the whole Unirest usage and every method call on it as the mock returns null by default.
If you want to test your HTTP clients take a look at WireMock or the MockWebServer from OkHttp. This way you test your clients with real HTTP communication and can test also corner cases like slow responses or 5xx HTTP codes.

Unit testing a method that calls a method on newly created instance?

We need to write junit test for below method.
public void Logout(){
new SecurityContextLogoutHandler.logout();
}
How can we test where securitycontextLogoutHandler.logout method is called?
We are able to verify that a new instance of securitycontextLogoutHandler is created by usinf PowerMockito but not able to verify logout method call.
Below is the Test written:
SecurityContextLogoutHandler securityContextLogoutHandler =
PowerMockito.mock(SecurityContextLogoutHandler.class);
PowerMockito.verifyNew(SecurityContextLogoutHandler.class);

Spring Transaction Doesn't Rollback

We have a Spring Transaction rollback issues, where rollback doesn't seems to be working.
Within my service layer method which is annotated with #Transactional I call three different DAOImpl classes to insert 3 records. The middle insert do a get from a 4th table to populate a description field but this get failed. I expect the first insert to rollback but it doesn't seems to be happening.
Few Points:
The 'Get' method throws a Runtime Exception
We are using org.springframework.jdbc.datasource.DataSourceTransactionManager and MySQL datasource defined in applicationContext.xml. Beans are created in Beans.xml which is imported into ApplicationContext.xml
No #Transactional annotation in DAO layer
We have used <tx:annotation-driven transaction-manager="transactionManager"/> again in applicationContext.xml
We are using Spring 3.1
UPDATE:
Code snippets....
Service Class- This is somthing similar to what I have .... I tested with and without #Autowired. The transaction enable method is called within the service class.
public class CustomerService {
//#Autowired
CustomerOrderDAO customerOrderDAOImpl;
//#Autowired
CustomerItemDAO customerItemDAOImpl;
//#Autowired
CustomerPromotionDAO customerPromotionDAOImpl;
//#Autowired
PromotionDAO promotionDAOImpl;
//other variables
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) {
try {
saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
#Transactional
public void saveOrderDetails(CustomerOrder customerOrder) throws Exception {
customerOrderDAOImpl.create(customerOrder);
....
while (promotionsIterator.hasNext()) {
customerPromotion.setPromotionName(promotionDAOImpl.getName(customerOrder.getPromotionId));
customerPromotionDAOImpl.create(customerPromotion);
}
......
while (customerItemIterator.hasNext()) {
customerItemDAOImpl.create(customerItem);
}
}
}
Any idea?
Thanks.
The default behaviour of #Transactional is that transactional behaviour is added with a proxy around the object (the CustomerService in your example). From the reference docs (scroll down):
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional.
In your example, an external call to the handlingIncomingOrders() passes through the proxy and hits the target object (an instance of the CustomerService). However, the subsequent call to saveOrderDetails() is a normal method call inside the target object, thus the transactional behaviour in the proxy is never invoked. However, if the saveOrderDetails() was called from another class, you will find that the transactional behaviour will work as expected.
The solution in your case would be calling saveOrderDetails(customerOrder); as proxyBean.saveOrderDetails(customerOrder); Where proxybean is the Object on whichhandleIncomingOrders` is being called.
If CustomerService is singleton (Defualt scope) it can be as simple as adding below code to the Service class. (adding a self reference as autowired)
//#Autowired
CustomerService customerService; // As this is injected its a proxy
and in the Method use it as
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
If its scope is Prototype the one of possible simple solution will be as follows.
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder, CustomerService customerService) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
And where you are calling handleIncomingOrders use changes suggested in below code.
bean.handleIncomingOrders(customerOrder); //Suppose this is old code
Change it to
bean.handleIncomingOrders(customerOrder, bean);// THough it appears as we are sending reference to `THIS` as parameter whcihc can be unnecessary, in case of `Proxy`while inside your method `this` and `Passed reference` will point to different Obejects.

Resources