I am trying to write testcases for a method I've implemented that in turn uses a third party cache provider.
The problem I am facing is that the cache is asyncronous, making it quite hard to test since the element put into cache are not instantly in the cache.
My solution to this was to just mock the cache using PowerMockito.
I can make it so that it always returns the same object, but preferable I want it to put the object into a HashMapon put and get it from the same map on a get operation.
The get operation should be pretty simple, something like:
final Map<String, Object> cacheMap = new HashMap<>();
Answer<Object> getFunction = invocation ->
cacheMap.get(invocation.getArgument(0));
when(mockCache.get(any())).thenAnswer(getFunction);
But I am not sure how to mock a similar call for the void method mockCache.put(any(), any())
It atleast seems as if you cannot mock void functions to anything other than calling the real method or doing nothing.
I think you are looking for intercepting the original call and rerouting it to a different implementation. Have a look at this answer for an explanation how to do it.
Related
I have the following test case:
ClassPathResource resource = new ClassPathResource(...);
doReturn(resource.getInputStream()).when(someMock).getInputStream();
where I read some resource and return it in my test. This method is called with some uncertainty in an asynchronous, scheduled manner in the actual production code - hence I do not have complete control over how many times it is exactly called, although the returned data is always the same (or should be).
In other words, this can potentially cause a randomly failing test if the method is invoked and the stream is read more times than expected, since the stream has not (and cannot) be reset, and is already at EOF.
I explicitly do not wish to have this be invoked synchronously in the test context, and am using Awaitility.await() to test these kinds of scenarios, so unfortunately that is not an option for me.
Now, the 'dumb' way to potentially fix this is something like the following:
doReturn(resource.getInputStream()).doReturn(resource.getInputStream()).<...>.when(someMock).getInputStream();
But this still does not fix the actual issue and is a band-aid at best.
I was actually expecting something like the following to work:
ClassPathResource resource = new ClassPathResource(...);
doReturn(resource.call().getInputStream()).when(someMock).getInputStream();
but unfortunately, this also retrieves the underlying Stream only once.
How can I provide a fresh instance on every doReturn() call? Can mockito even do this? Is there an alternative approach to what I wish to do?
I'm not totally sure I'm on board with what you're asking.
You're first doing ClassPathResource resource = new ClassPathResource(...);, which I'm assuming is a one time thing. And then you are returning resource.getInputStream() for every invocation. By definition, you can't have multiple instances then - you're asking for one thing and trying to do another. So what is it that you want? You could use some question restructuring. Also, what are you doing with ClassPathResource in a unit test in the first place?
In the meantime, the best I can guess of what you want is the most literal interpretation of your question that I can get to, and completely ignoring any and all psudeo-code (because it completely contradicts your question). That is, you want a completely separate instance of an InputStream for every invocation to a method. This part is easy.
Mockito.doAnswer(new Answer<InputStream>() {
#Override
public InputStream answer(InvocationOnMock invocation)
throws Throwable {
return Mockito.mock(InputStream.class);
}
}).when(resource.getInputStream());
I have a simple method that I have annotated for caching.
#Cacheable(value = "devices", key = "#hardwareId", unless = "#result == null")
public Device get(String hardwareId)
I have a mechanism to know when someone changes the underlying database. So that I know to Evict a member from the cache, so that the next call in will go back to the database.
getCache().remove(hardwareId);
What I would like to do it REPLACE the element in the cache. The reason for this is that the call back to the database can take 1000ms & I'd like to not have that blip on the performance of the method.
As far as I can tell I have two options.
Option 1:
When I evict the member, call back into the service at that time.
getCache().remove(hardwareId);
service.get(hardwareId);
Option 2:
Create an instance of 'net.sf.ehcache.bootstrap.BootstrapCacheLoader'
that registers on startup the same class to be notified element
being removed from a cache (notifyElementRemoved()).
On #PostContruct get all methods annotated with #Cacheable. Create a Map of
'cacheName' to Method instance (java reflection Method)
When notifyElementRemoved() is triggered, uses the cache name to get the Method instance, with that invoke it to trigger the cache to be repopulated.
Method method = map.get(cacheName);
// Add magic here to get the service.
Object serviceInstance = applicationContext.getBean("deviceService");
if (Proxy.isProxyClass(serviceInstance.getClass())) {
Proxy.getInvocationHandler(serviceInstance).invoke(serviceInstance, method, new Object[] {objectKey});
} else {
method.invoke(serviceInstance, objectKey);
}
The downside of option 1 is that I have to go modify 30+ classes to put in the logic to call back into the service.
The downside of option 2 is that it's a bit complex, it feels like it would be good if ehCache could provide this feature. It knows what method it wrapped, it knows what the key/parameters were that called into this method.
The downside of both options is that there will always be a time when the cache does not contain the member & could cause a blip in performance.
My question is, does ehCache provide the feature I want or is there another mechanism out there to do REPLACEMENT of members in the cache with zero time of the cache being empty?
Don't do option 2. Too complicated. In general, the way it goes is to have a #Cacheable and a #CachePut method. Why not using that?
#Cacheable(value = "devices", key = "#hardwareId", unless = "#result == null")
public Device get(String hardwareId)
#CachePut(value ="devices", key= "#hardwardId", unless = "#result == null")
public Device update(String hardwareId)
It should cleanly solve your problem.
BTW, you don't need to specify the key. It is implicit.
Simplifying a bit, our system has two parts. "Our" part, which in turn uses an lower level part implemented by another team (in the same codebase). We have a fairly complicated functional test setup, where we wrap the entry points to the lower level in spy objects. In positive tests we use the real implementation of that level, but we mock calls that should fail with some predefined error.
Now I am trying to add support for more complicated scenarios, where I would like to add an artificial delay for the calls made to the underlying level (on a fake clock obviously). To do this I would like to define a mock that would (1) Call the real implementation (2) Get the resulting Future object that is returned and combine it with a custom function that would inject the delay accordingly. So Ideally I would like to have something like:
doAnswer(invocationOnMock ->
{
result = call real method on mySpy;
return Futures.combile(result, myFunction);
}).when(mySpy).myMethod();
How can I achieve it?
As for me the easiest way it's just to save the link to the read object when you initialize your Spy object:
Foo realFoo = new Foo();
Foo spyFoo = Mockito.spy(realFoo);
Now you can stub it like this:
doAnswer(invocation -> realFoo.getSome() + "spyMethod").when(spyFoo).getSome();
One more way is to call invocation.callRealMethod():
doAnswer(invocation -> invocation.callRealMethod() + "spyMethod").when(spyFoo).getSome();
But in this case you may need to cast the return value as long as invocation.callRealMethod() returns Object.
Suppose I want to create a unit test for a method like this:
public Car map(CarReq request) {
Car car = new Car();
car.setPrice(carReq.getPrice());
car.setColour(carReq.getColour());
car.setType(carReq.getType());
// Other 20 lines like these
return car;
}
I can mock carRequest and tell each method what should return. But that's like not testing anything, as all the method does is getting values from carReq.
I can create a testing carReq object (without mocking) and check that the same values are copied into the output Car object. But that's a lot of work, right?
Isn't there a more intelligent way?
You want to test the logic of the method.
Therefore if what the method does is copying the properties of a CarReq into a Car, then this is what you should test:
#Test
public void mapTest() {
// Given
CarReq carReq = new CarReq(10000D, ...);
// When
Car car = myClass.map(carReq);
// Then
Assert.assertEquals(car.getPrice(), carReq.getPrice());
// ...
}
I'm not quite sure what the issue is ? Surely since the method takes a request and returns a new Car, that's precisely what you want to test ? If I was doing it, I would:
create a populated request and determine that the Car fields are what are in the request
perhaps assert that each invocation gives you a new Car ?
assert expected behaviour if you pass in a null (again, depending on the proposed usage of the method)
You say that all the method does is call setters/getters, but don't forget that one purpose of a unit test is to assert that the behaviour remains the same going forwards (i.e. you're testing for regressions). If you add additional functionality to this method, and you accidentally break something, the above test will tell you immediately.
Is it a lot of work ? Maybe (perhaps a few mins of copy/paste getter/setter invocations and changing params to be unique per attribute). But it's a lot less work than resolving an issue in production later on.
I can create a testing carReq object (without mocking) and check that
the same values are copied into the output Car object. But that's a
lot of work, right?
It is, but if you really are willing to unit-test this method, you have to do this.
Please note that you can use libraries like Orika to perform this kind of dumb field-mapping methods for you. Saves time and code lines :)
I am trying to make some test classes to test whether caching in my project works correctly. The easiest way to do so would be something like this:
MyCache cache = new MyCache(new MyDataSource());
MyResult = cache.load(somepath); //This calls some method MyDataSource.getData which is expensive
//Here the thing I need comes
Magic.cleanStackTrace(); //Prepare clean buffer for all called methods
//Call the cache load again
cache.load(somepath);
//Check if expensive MyDataSource.getData has been called
List<Method> methodsCalled = Magic.getAllFunctionsCalledAfterClean(); //Again, fictional finction
//Loop through lost and check if MyDataSource.getData is there or not
This would allow me to ensure that everything is cached as well as that the cache is being deleted when it should. I can also imagine other tests with different purpose - such as security, cleanup from debug methods and so on.
Is this possible? In this case, I think there's no shame in super dirty solution as it's just testing and everything is allowed.