I am trying to test a method methodB (as shown in the code below). I want to return directly from methodA without going into the actual code of methodA.
I have used when/thenReturn and doReturn/when but didn't get any success. The test case goes into the real code of methodA. Also tried using spy with Class A instance but didn't get any success.
Actual Class
class A{
fun methodA(String a): String{
// do something
throw new Exception("An error occured");
}
fun methodB(String b): String{
try{
methodA("test")
} catch (e: Exception){
println(e.message());
}
}
}
Test Class
class ATest{
private lateinit var a: A
#Before
fun setUp() {
a= A() // I am initializing services in real scenario
}
#Test
fun `when methodB is not valid then throw Exception`(){
val aMock = mock(A)
Mockito.when(aMock.methodA("test") )
.thenThrow(UserException.INVALID_REQUEST())
// When
val exception: Exception = Assert.assertThrows(
UserException::class.java
) {
a.methodB("test b")
}
val expectedMessage = "INVALID"
val actualMessage = exception.message
// Then
Assert.assertTrue(actualMessage!!.contains(expectedMessage))
}
}
Can anyone please help?
val a = A()
val aSpy = Mockito.spy(a)
Mockito.when(aSpy.methodA(ArgumentMatchers.any())).thenThrow(UserException.INVALID_REQUEST())
you need to get a real instance of class A and then wrap it inside a programmable wrapper which is a spy.
The param matcher of the when statement is the 2nd point of failure since "Test" is not the same instance then the "test b" string. So you dont need to verify some parameter so skip it.
If you want to verify the used parameter you can use a captor instead of ANY().
Related
I have an authorizaton Aspect that checks specific conditions based on method annotation.
This specific example shows annotation to mark a method that is only accessible by customer service. But unfortunately this isn't the only condition.
We have to confirm the customerServiceId that is also passed as one of method parameters. The parameter containing customerServiceId is pretty nested, so I was wondering if it's possible to get parameter value by some kind of a "path".
So let's say we have this method:
fun updateRemoteConfig(val remoteConfig: RemoteConfig) { doSomething() }
RemoteConfig class is pretty nested, so the path to customerServiceId would be something like: remoteConfig.customerService.id
What I would like to achieve is mark the method with annotation:
#CustomerServiceAccess(customerServiceIdPath = "remoteConfig.customerService.id")
And the value would then be fetched inside Aspect method. But I have no idea how to get to the specified value by path. Is it even possible?
The unknown is where arrows are in the code. Here's rest of the aspect:
#Aspect
class AuthorizationAspect {
#Pointcut("#annotation(com.my.project.annotations.CustomerServiceAccess)")
fun customerServiceAccess() = Unit
#Before("customerServiceAccess()")
fun checkAccess(joinPoint: JoinPoint) {
val methodSignature = joinPoint.signature as MethodSignature
val method = methodSignature.method
val canAccess = mutableListOf<() -> Boolean>()
.apply {
addAll(method.getAnnotationsByType(CustomerServiceAccess::class.java).map { it.canAccess(method) })
}
.any { it() }
if (!canAccess) {
throw UnauthorizedException(message = "User cannot perform this action")
}
}
private fun CustomerServiceAccess.canAccess(val method: Method): () -> Boolean = {
->> val customerServiceIdParam = method.getParameterByPath(getCustomerServiceIdPath())
SecurityContext.isCustomerService && SecurityContext.customerServiceId == customerServiceIdParam
}
private fun CustomerServiceAccess.getCustomerServiceIdPath(): String = this.customerServiceIdPath
}
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.FUNCTION)
annotation class CustomerServiceAccess(val customerServiceIdPath: String)
I'm not allowed to post real code, but this is basically what's going on:
We have a class InterfaceOneImpl that implements an interface InterfaceOne and a InterfaceTwoImpl that implements an InterfaceTwo
InterfaceTwoImpl gets instantiated in InterfaceOneImpl, and InterfaceTwoImpl.makeHttpRequest() gets called, but I need to mock this function in my unit tests because I obviously don't want to make http requests in them. makeHttpRequest is a public, non-static function that returns a String
My code does something like this:
public class InterfaceOneImpl implements InterfaceOne{
public String processRequest(...){
...
InterfaceTwo obj = new InterfaceTwoImpl();
obj.makeHttpRequest();
...
}
}
My test class looks like this:
public TestInterfaceOneImpl {
....
#Test
public void testProcessRequest(){
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
PowerMockito.whenNew(RiskValidationRestClientImpl.class).withNoArguments().thenReturn((RiskValidationRestClientImpl) mock);
String reqStr = interfaceOneImpl.processRequest();
//a bunch of failed assertions
}
}
My issue is that processRequest() is not being mocked properly, because the source code version of the method is actually being run rather than the mock. When I step through each line of my unit test in debug mode, I always end up in the body of the makeHttpRequest() function. What am I doing wrong?
My issue is that processRequest() is not being mocked properly, because the source code version of the method is actually being run rather than the mock. When I step through each line of my unit test in debug mode, I always end up in the body of the makeHttpRequest() function.
I think your question is wrong - processRequest, based on your example, is a method on InterfaceOne while mock is an instance of InterfaceTwo.
I assume you meant:
InterfaceTwo.when(mock.makeHttpRequest()).thenReturn("zzzz");
In any case ...
What am I doing wrong?
You think you're mocking something when you're not at all. Let's break down your example:
// First you create an instance of InterfaceOneImpl - OK
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
// Next you create a mock of InterfaceTwo (I think? I don't use PowerMock) - OK
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
// Then you tell the mock you created that it should return "zzzz" - OK
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// Finally you call a method on your instance. YOU DO NOT USE "mock" in
// any way shape or form. As it's defined, "processRequest" creates a NEW
// instance of InterfaceTwo: InterfaceTwo obj = new InterfaceTwoImpl();
// and uses THAT instance. So of course you will always end up with the
// real method being called. You're creating a mock and literally never
// using it.
String reqStr = interfaceOneImpl.processRequest();
To fix: actually use your mock. Either by passing it in the function:
// Pass the object to use as an argument
public String processRequest(InterfaceTwo obj){
...
obj.makeHttpRequest();
...
}
// And then your test:
#Test
public void testProcessRequest() {
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// NOW you can use the mock
String reqStr = interfaceOneImpl.processRequest(mock);
}
Or by passing it through to the class:
public class InterfaceOneImpl implements InterfaceOne {
public InterfaceOneImpl(InterfaceTwo obj) {
this.obj = obj;
}
public String processRequest(...){
...
obj.makeHttpRequest();
...
}
}
// And then your test
#Test
public void testProcessRequest(){
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// Now interface one will use the mock to do the request
InterfaceOne interfaceOneImpl = new InterfaceOneImpl(mock);
String reqStr = interfaceOneImpl.processRequest();
//a bunch of failed assertions
}
I have unit test in which I am trying to check is a use case is called with the right parameters but I get an error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method com.xx.xxx.clean.orderview.domain.OnStandUseCaseCoroutine$Params.<init>, parameter serviceType
#Test
fun `when notifyOnStand is called then we create a TimestampedAction with the correct user id, vehicle, timestamp and pass that to the usecase`() {
val actionCaptor = argumentCaptor<TimestampedAction>()
val timestamp = DateTime.now()
every(noServiceRequiredBus.get()).thenReturn(Observable.just(REQUESTED))
every(timingsUpdater.timestampCalculator(any(), any())).thenReturn(timestamp)
baseOrderViewPresenter.setView(view)
baseOrderViewPresenter.notifyOnStand()
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(any(), any(), capture(actionCaptor)))
}
}
Use case which will get called when when called baseOrderViewPresenter.notifyOnStand() from tets case
class OnStandUseCaseCoroutine #Inject constructor(
private val orderRepository: OrderRepository,
private val serviceOrderTypeProvider: ServiceOrderTypeProvider
) : UseCaseCoroutine<GenericResponse, OnStandUseCaseCoroutine.Params> (){
override suspend fun run(params: Params) =
orderRepository.notifyOnStandSuspend(serviceOrderTypeProvider.apiPathFor(params.serviceType), params.id, params.action)
data class Params(val serviceType: String, val id: String, val action: TimestampedAction)
}
Presenter layer which has the call to use case
private fun onstandUseCaseCoroutines(serviceType: String, id: String, action: TimestampedAction, callback: (GenericResponse?) -> Unit) {
try {
onStandUseCaseCoroutine(OnStandUseCaseCoroutine.Params(serviceType, id, action)) {
callback.invoke(it)
}
} catch (exception: Exception) {
onStandResponseErrors()
}
}
how can I fix this please
I tried changing to bellow code but that did not fix it, I am not sure what to do the capture(actionCaptor) bit if that is the issue
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(anyString(), anyString(), capture(actionCaptor)))
}
Any suggestions please
Thanks
R
I want to test this class, so it will shows me that I call ws with right params:
class MyService {
public static boolean sendEmail(MyWebService ws) {
if (!ws.sendCustomEmail("me#example.com", "Subject", "Body")) {
throw new RuntimeException("can't do this");
}
// ... some more logic which can return false and should be tested
return true;
}
}
Is there a way to combine mockito spy and thenReturn? I like how spy will show actual methods calls and not just simple message about assertionFailed.
#Test
void myTest() {
MyService spyWs = Mockito.spy(MyWebService.class);
// code below is not working, but I wonder if there is some library
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
)
.thenReturn(true);
MyService::sendEmail(spyWs);
}
What I want as a result is error message showing me the difference between parameters that expected and actual like usual spy's:
Test failed:
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("here should be another body and test should show diff")) was never called
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("Body")) was called, but not expected
Expected:
I know I can do just stub and then test for exception, but thats will not show the difference in parameters
When using a Spy, use the doReturn().when() syntax. Also verify after the set-up:
MyService spyWs = Mockito.spy(MyWebService.class);
doReturn(true).when(spyWs).sendCustomEmail(any(), any(), any());
MyService::sendEmail(spyWs);
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
);
// assert that sendMail returned true;
Frankly i dont think you need to verify here, just a boolean assertion would be enough but thats up to you.
I'm trying to write some unit-test cases for a class with functions that has callbacks as arguments (Please see code below)
class NetworkApi(private val url: String) {
fun getToken(listener: (String) -> Unit) {
Thread(Runnable {
Thread.sleep(2000)
if (TextUtils.isEmpty(url)) listener("")
else listener("Dummy token")
}).start()
}
}
and the unit test case is
#RunWith(AndroidJUnit4::class)
class NetworkApiTest {
var networkApi: NetworkApi? = null
#Test
fun testEmptyToken() {
networkApi = NetworkApi("")
networkApi?.getToken {
Assert.assertThat(it, isEmptyOrNullString())
}
}
}
And whenever I run this test case, I do get success all the time, no matter what values I send. I know that I'm not doing exact way.
Can someone please help me writing unit test cases for classes in JUnit.
The problem is that the test finishes before the callback is invoked and the assert is in the wrong thread.
You have to copy the result from the callback back to the main thread. Use a CompletableFuture.
If you like to fail the test after a period of time you can use the get method with a timeout value:
#RunWith(AndroidJUnit4::class)
class NetworkApiTest {
var networkApi: NetworkApi? = null
#Test
fun testEmptyToken() {
val future = CompletableFuture<String>()
networkApi = NetworkApi("")
networkApi?.getToken {
future.complete(it)
}
val result = future.get(3,TimeUnit.SECONDS)
Assert.assertThat(it, isEmptyOrNullString())
}
}