I have to test a method which uses a mutable object
private final List<LogMessage> buffer;
...
flushBuffer() {
sender.send(buffer);
buffer.clear();
}
I need to test that it sends buffers with exact size.
ArgumentCaptor is not applicable because the captured collection is clear by the time of assertion.
Is there a kind of matcher which can reuse Hamcrest's hasSize() and does check right in time of method call?
I would prefer something like this hypothetical collectionWhich matcher:
bufferedSender.flushBuffer();
verify(sender).send(collectionWhich(hasSize(5)));
A lightweight alternative to David's idea: Use an Answer to make a copy at the time of the call. Untested code, but this should be pretty close:
final List<LogMessage> capturedList = new ArrayList<>();
// This uses a lambda, but you could also do it with an anonymous inner class:
// new Answer<Void>() {
// #Override public Void answer(InvocationOnMock invocation) { /* ... */ }
// }
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> argument = (List<LogMessage>) invocation.getArguments()[0];
capturedList.addAll(argument);
});
bufferedSender.flushBuffer();
assertThat(capturedList).hasSize(5);
The Jeff Bowman answer is fine but I think that we can improve it by inlining the assertion in the Answer object itself. It avoids creating unnecessary copy objects and additional local variable(s).
Besides in cases of we need to copy the state of custom objects (by performing a deep copy of it), this way is much simpler. Indeed, it doesn't require any custom code or library to perform the copies as the assertion is done on the fly.
In Java 8, it would give :
import static org.mockito.Mockito.*;
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> listAtMockTime = invocation.getArguments()[0];
Assert.assertEquals(5, listAtMockTime.getSize());
});
bufferedSender.flushBuffer();
Note that InvocationOnMock.getArgument(int index) returns an unbounded wildcard (?). So no cast is required from the caller as the returned type is defined by the target : here the declared variable for which one we assign the result.
You would have the same issue than with ArgumenCaptor as the verify() method checks the invocation with the state of the object after the execution. No capture is performed to keep only the state at the invocation time.
So with a mutable object I think that a better way would be to not use Mockito and instead create a stub of the Sender class where you capture the actual size of the collection as send() is invoked.
Here is a sample stub class (minimal example that you could of course enrich/adapt) :
class SenderStub extends Sender {
private int bufferSize;
private boolean isSendInvoked;
public int getBufferSize() {
return bufferSize;
}
public boolean isSendInvoked(){
return isSendInvoked;
}
#Override
public void send(List<LogMessage> buffer ) {
this.isSendInvoked = true;
this.bufferSize = buffer.size();
}
}
Now you have a way to check whether the Sender was invoked and the size (or even more) of that.
And so put aside Mockito to create this mock and verify its behavior :
SenderStub sender = new SenderStub();
MyClassToTest myClass = new MyClassToTest(sender);
// action
myClass.flushBuffer();
// assertion
Assert.assertTrue(sender.isInvoked());
Assert.assertEquals(5, sender.getBufferSize());
Related
I'm trying to create a custom BodyPublisher that would deserialize my JSON object. I could just deserialize the JSON when I'm creating the request and use the ofByteArray method of BodyPublishers but I would rather use a custom publisher.
public class CustomPublisher implements HttpRequest.BodyPublisher {
private byte[] bytes;
public CustomPublisher(ObjectNode jsonData) {
...
// Deserialize jsonData to bytes
...
}
#Override
public long contentLength() {
if(bytes == null) return 0;
return bytes.length
}
#Override
public void subscribe(Flow.Subscriber<? super ByteBuffer> subscriber) {
CustomSubscription subscription = new CustomSubscription(subscriber, bytes);
subscriber.onSubscribe(subscription);
}
private CustomSubscription implements Flow.Subscription {
private final Flow.Subscriber<? super ByteBuffer> subscriber;
private boolean cancelled;
private Iterator<Byte> byterator;
private CustomSubscription(Flow.Subscriber<? super ByteBuffer> subscriber, byte[] bytes) {
this.subscriber = subscriber;
this.cancelled = false;
List<Byte> bytelist = new ArrayList<>();
for(byte b : bytes) {
bytelist.add(b);
}
this.byterator = bytelist.iterator();
}
#Override
public void request(long n) {
if(cancelled) return;
if(n < 0) {
subscriber.onError(new IllegalArgumentException());
} else if(byterator.hasNext()) {
subscriber.onNext(ByteBuffer.wrap(new byte[]{byterator.next()));
} else {
subscriber.onComplete();
}
}
#Override
public void cancel() {
this.cancelled = true;
}
}
}
This implementation works, but only if subscriptions request method gets called with 1 as a parameter. But that's what happens when I am using it with the HttpRequest.
I'm pretty sure this is not any way preferred or optimal way of creating the custom subscription but I have yet to found better way to make it work.
I would greatly appreciate if anyone can lead me to a better path.
You are right to avoid making a byte array out of it, as that would create memory issues for large objects.
I wouldn’t try to write a custom publisher. Rather, just take advantage of the factory method HttpRequest.BodyPublishers.ofInputStream.
HttpRequest.BodyPublisher publisher =
HttpRequest.BodyPublishers.ofInputStream(() -> {
PipedInputStream in = new PipedInputStream();
ForkJoinPool.commonPool().submit(() -> {
try (PipedOutputStream out = new PipedOutputStream(in)) {
objectMapper.writeTree(
objectMapper.getFactory().createGenerator(out),
jsonData);
}
return null;
});
return in;
});
As you have noted, you can use HttpRequest.BodyPublishers.ofByteArray. That is fine for relatively small objects, but I program for scalability out of habit. The problem with assuming code won’t need to scale is that other developers will assume it is safe to pass large objects, without realizing the impact on performance.
Writing your own body publisher will be a lot of work. Its subscribe method is inherited from Flow.Publisher.
The documentation for the subscribe method starts with this:
Adds the given Subscriber if possible.
Each time your subscribe method is called, you need to add the Subscriber to some sort of colllection, you need to create an implementation of Flow.Subscription, and you need to immediately pass it to the subscriber’s onSubscribe method. Your Subscription implementation object needs to send back one or more ByteBuffers, only when the Subscription’s request method is called, by invoking the corresponding Subscriber’s (not just any Subscriber’s) onNext method, and once you’ve sent all of the data, you must call the same Subscriber’s onComplete() method. On top of that, the Subscription implementation object needs to handle cancel requests.
You can make a lot of this easier by extending SubmissionPublisher, which is a default implementation of Flow.Publisher, and then adding a contentLength() method to it. But as the SubmissionPublisher documentation shows, you still have a fair amount of work to do, for even a minimal working implementation.
The HttpRequest.BodyPublishers.of… methods will do all of this for you. ofByteArray is okay for small objects, but ofInputStream will work for any object you could ever pass in.
I have a class like below, with hundreds of methods:
public class APIMethods {
public ToView toView;
public APIMethods(ToView toView) {
this.toView = toView;
}
public static final int SUCCESS = 1;
public static final int ERROR = 0;
public void registerAnonymous(String deviceId, String installRef, final int requestCode) {
APIInterface apiService =
RetrofitClientInstance.getRetrofitInstance().create(APIInterface.class);
JsonObject obj = new JsonObject();
obj.addProperty("androidId", deviceId);
obj.addProperty("projectId", 0);
obj.addProperty("ChannelName", installRef);
Call<Response<BasicUser>> call = apiService.registerAnonymous("application/json", Utils.getFlavorId(), obj);
call.enqueue(new Callback<Response<BasicUser>>() {
#Override
public void onResponse(Call<Response<BasicUser>> call, Response<Response<BasicUser>> response) {
Response<BasicUser> mResponse;
try {
mResponse = response.body();
if (mResponse.getErrorCode() == 0)
toView.updateView(requestCode, SUCCESS, mResponse);
else
toView.updateView(requestCode, ERROR, mResponse);
} catch (Exception e) {
mResponse = new Response<>();
mResponse.setErrorCode(-1);
toView.updateView(requestCode, ERROR, mResponse);
e.printStackTrace();
}
}
#Override
public void onFailure(Call<PetMarkResponse<BasicUser>> call, Throwable t) {
Response<BasicUser> numberValidationResponse = new Response<BasicUser>();
numberValidationResponse.setErrorCode(-1);
toView.updateView(requestCode, ERROR, numberValidationResponse);
}
});
}
///And dozens of such method
}
So in my other classes everywhere in my application, I simply instantiate the class and call the method that I want:
APIMethods api = new APIMethods(this);
api.registerAnonymous(Utils.getAndroidId(this), BuildConfig.FLAVOR, STATE_REGISTER_ANONYMOUS);
My question is how expensive this object (api) is? Note that in each class, a few methods of the object are called.
The object is not expensive at all.
An object contains a pointer to the object's class, and the methods are stored with the class. Essentially, the methods are all shared. An object of a class with no methods and an object of a class with 10000 methods are the same size (assuming everything else is equal).
The situation would be different if you had 100 fields instead of 100 methods.
You may want to think about if having hundreds of methods in a single class is a good idea. Is the code easy to understand and maintain? Is this an example of the "God object" anti pattern? https://en.m.wikipedia.org/wiki/God_object
This seems like a classic example of the XY problem. Your actual problem is how to make the code readable, but you're actually asking about whether a class with hundreds of methods is expensive.
It being expensive is the least of your concerns - you should be more worried about maintenance. There's no reason at all that any class should ever be that large, especially if you have a lot of independent methods and each class is only calling a few of them. This will make the class very hard to understand - having them all in one place will not improve the situation.
Some of the comments have already pointed this out, but you should, at a minimum, break this up topically.
Even better, refactor this to the Strategy pattern and use a Factory to pick which one to use. That will meet your goal of ease of use while avoiding the problem of having hundreds of unrelated methods in one place.
Try to define a Cohesive class, untill and unless the methods are written relevant to the class and it defines its purpose.
Below link describe the importance of methods for a class:
https://www.decodejava.com/coupling-cohesion-java.htm
I am working on a project which provides a list of operations to be done on an entity, and each operation is an API call to the backend. Let's say the entity is a file, and operations are convert, edit, copy. There are definitely easier ways of doing this, but I am interested in an approach which allows me to chain these operations, similar to intermediate operations in java Streams, and then when I hit a terminal operation, it decides which API call to execute, and performs any optimisation that might be needed. My API calls are dependent on the result of other operations. I was thinking of creating an interface
interface operation{
operation copy(Params ..); //intermediate
operation convert(Params ..); // intermediate
operation edit(Params ..); // intermediate
finalresult execute(); // terminal op
}
Now each of these functions might impact the other based on the sequence in which the pipeline is created. My high level approach would be to just save the operation name and params inside the individual implementation of operation methods and use that to decide and optimise anything I'd like in the execute method. I feel that is a bad practice since I am technically doing nothing inside the operation methods, and this feels more like a builder pattern, while not exactly being that. I'd like to know the thoughts on my approach. Is there a better design for building operation pipelines in java?
Apologies if the question appears vague, but I am basically looking for a way to build an operation pipeline in java, while getting my approach reviewed.
You should look at a pattern such as
EntityHandler.of(remoteApi, entity)
.copy()
.convert(...)
.get();
public class EntityHandler {
private final CurrentResult result = new CurrentResult();
private final RemoteApi remoteApi;
private EntityHandler(
final RemoteApi remoteApi,
final Entity entity) {
this.remoteApi = remoteApi;
this.result.setEntity(entity);
}
public EntityHandler copy() {
this.result.setEntity(new Entity(entity)); // Copy constructor
return this;
}
public EntityHandler convert(final EntityType type) {
if (this.result.isErrored()) {
throw new InvalidEntityException("...");
}
if (type == EntityType.PRIMARY) {
this.result.setEntity(remoteApi.convertToSecondary(entity));
} else {
...
}
return this:
}
public Entity get() {
return result.getEntity();
}
public static EntityHandler of(
final RemoteApi remoteApi,
final Entity entity) {
return new EntityHandler(remoteApi, entity);
}
}
The key is to maintain the state immutable, and handle thread-safety on localized places, such as in CurrentResult, in this case.
Suppose I have a code to test
void myMethod()
{
byte []data = new byte[1];
data[0]='a';
output.send(42, data);
data[0]='b';
output.send(55, data);
}
I write a test:
testSubject.myMethod();
verify(output).send(eq(42), aryEq(new byte[]{'a'}));
verify(output).send(eq(55), aryEq(new byte[]{'b'}));
The test will fail as the method implementation reuses the same array for both calls, it is impossible to match args of the first send invocation after method finishes, so techically the verify statements should be specified before the method call, something like an expectation.
What is the right way to test such methods?
Well it looks like Mockito is a bit inconvenient here. It detects the method call and logs it (use mock(MyOutput.class, withSettings().verboseLogging()); to enable logging), but it stores the reference to the array you're passing and thus is influenced when you mutate the array. It then thinks the method call was send(42, [98]) rather than send(42, [97]).
A possible way to work with that is to use the expectations you've mentioned. For example you can use a counter and increment it if a call matched the expectations (it is really just a workaround and rather nasty):
MyOutput mock = mock(MyOutput.class, withSettings().verboseLogging());
Main subject = new Main(mock);
AtomicInteger correctCallsCounter = new AtomicInteger(0);
doAnswer(invocation -> correctCallsCounter.incrementAndGet()).when(mock).send(eq(42), aryEq(new byte[]{'a'}));
doAnswer(invocation -> correctCallsCounter.incrementAndGet()).when(mock).send(eq(55), aryEq(new byte[]{'b'}));
subject.myMethod();
assertThat(correctCallsCounter.get(), is(2));
It works, because doAnswer is triggered when the call happens and when the byte array hasn't been changed yet.
The big downside of this workaround is, that it only works with void methods. If send would return "something", then I currently don't see a way to work around that.
Well and the other one is that this is obviously a rather nasty workaround.
So I would suggest to refactor your code a bit (use a new array) if that is possible. That would avoid these issues here.
If your send method would indeed return something and your myMethod method would rely on it, then you would usually mock it this way (send is expected to return a String in this example):
when(mock.send(eq(55), aryEq(new byte[]{'b'}))).thenReturn("something");
In order to still use the above mentioned workaround, you could change the doAnswer method to increment your counter and return your String (which you would mock anyway, thus it isn't that bad):
doAnswer(invocation -> {
correctCallsCounter.incrementAndGet();
return "something";
}).when(mock).send(eq(42), aryEq(new byte[]{'a'}));
Use an Answer to copy the value of the parameter.
Here is some code (it is not pretty):
public class TestMyClass
{
private static List<byte[]> mockDataList = new ArrayList<>();
#InjectMocks
private MyClass classToTest;
private InOrder inOrder;
#Mock
private ObjectClass mockOutputClass;
#After
public void afterTest()
{
inOrder.verifyNoMoreInteractions();
verifyNoMoreInteractions(mockOutputClass);
}
#Before
public void beforeTest()
{
MockitoAnnotations.initMocks(this);
doAnswer(new Answer()
{
#Override
public Object answer(
final InvocationOnMock invocation)
throws Throwable
{
final byte[] copy;
final byte[] source = invocation.getArgument(1);
copy = new byte[source.length];
System.arraycopy(source, 0, copy, 0, source.length);
mockDataList.add(copy);
return null;
}
}).when(mockOutputClass).send(anyInt(), any(byte[].class));;
inOrder = inOrder(
mockOutputClass);
}
#Test
public void myMethod_success()
{
byte[] actualParameter;
final byte[] expectedFirstArray = { (byte)'a' };
final byte[] expectedSecondArray = { (byte)'b' };
classToTest.myMethod();
actualParameter = mockDataList.get(0);
assertArrayEquals(
expectedFirstArray,
actualParameter);
inOrder.verify(mockOutputClass).send(eq(42), any(byte[].class));
actualParameter = mockDataList.get(1);
assertArrayEquals(
expectedSecondArray,
actualParameter);
inOrder.verify(mockOutputClass).send(eq(55), any(byte[].class));
}
}
Note that the value of the parameter is compared separate of the verification of the call, but the order of the parameters is still verified (i.e. 'a' array first, then 'b' array).
For public method calls, EasyMock's capture() allows you to intercept & examine arguments passed to the method. For private method calls, PowerMock's expectPrivate lets you mock private method calls.
Is there a way to somehow combine these and get the arguments passed to a private method call? Example:
public class Program
{
public FancyReturnType PublicMethod()
{
ArbitraryType localInstance = new ArbitraryType();
localInstance.setFoo(somePrivateHelperMethod());
localInstance.setBar(increasinglyComplexMagic());
long aLongValue = 11235L;
// more variables, more work
SomeType worker = privateHelperToIntercept(localInstance, aLongValue, otherVariables);
if (worker.something)
{
return retVal.aFancyReturnType;
}
else
{
return retVal.anotherFancyReturnType;
}
}
}
In this case, I want to examine the localInstance object as it is consumed by the privateHelperToIntercept() call.
I've found plenty of examples to mock private method calls; PowerMock's expectPrivate(partiallyMockedObject, "nameOfPrivateMethod", arg1, arg2) works great. I've also found examples to intercept arguments passed to public method calls; Capture<Type> myTestCapture = new Capture<Type>() combined with someMockedObject.PublicMethod(capture(myTestCapture)).
Unfortunately, I can neither get the two to work together, nor find examples of combining them. Has anyone seen a way to do this?
FWIW, I suspect Mockito can do this, but it's not included in our source/build/test system. I'd like to avoid the process of supporting new libraries in our system if possible.
If you are asking how to get a reference to localInstance, then the following code should suffice.
#PrepareForTest(Program.class)
public class Test {
#Test
public void testMethod() {
ArbitraryType passedLocalInstance = new ArbitraryType();
PowerMock.expectNew(ArbitraryType.class).andReturn(passedLocalInstance );
//remainder of the test method
assertEquals(14.2, passedLocalInstance .getValue());
}
}
Since java is pass-by-reference, the passedLocalInstance will be the argument passed into the method call. Did that answer your question?
new of any type is simply a static method. Deal with it in the same way... wrap it in a method, stub out the method. In this case you want to return a mock in your test, and then you can test all the interactions with that object (and remove dependency in your test on the code within the object you are creating which should have it's own tests)
public Program {
// your above code up to object creation
ArbitraryType localInstance = createArbitraryType();
// rest of your above code here
ArbitraryType createArbitraryType() {
return new ArbitraryType();
}
}
in your test...
public class MyTest {
TestableProgram extends Program {
#Override
ArbitraryType createArbitraryType() {
return this.arbitraryTypeMock;
}
}
private ArbitraryType arbitraryTypeMock;
private TestableMyClass objectToTest = new TestableProgram();
// rest of your tests...
}
Given your constraint's that's how I'd do it.
If could bend your constraints a bit I'd loosen up on the private methods, I've generally done away with private in favor of package default to make testing easier. If the folks IN your package are misbehaving, it's usually your code so private is mostly protecting you from yourself anyway. (but I know that isn't a valid answer your question as posed... ).