How can I get mockito to record the values, and not only the object reference?
On 2 April 2013 12:10, Alexander Broekhuis <a.bro...@gmail.com> wrote:
How can I get mockito to record the values, and not only the object reference?
I don't think you can.
This sounds like a case where the tests might force you to make your code more resilient, for example by making your Data objects immutable.
Hi all,I have some existing code for which I am writing tests. In this code a pool of objects is used, and when calling a certain method on a mock, the argument is an entry for this pool. If the size of the pool is 1 (one). Only one object is used for each call.When I try to verify 3 calls with different properties placed in the argument, they only verify if I test against the last set of properties.In other words, since all calls use the same object (with different content), the mock doesn't record the previous calls. (it probably does, but since the value is overwritten the actual goal isn't achieved).
How can I get mockito to record the values, and not only the object reference?
TiA!Pseudo code without a pool, but with object reuse:public void test() {Sub mock = mock(Sub.class);ToTest obj = new ToTest(mock);obj.doo();// The first two are not validverify(mock).done(new Data("a")):verify(mock).done(new Data("b")):// The mock expects this one three timesverify(mock).done(new Data("c")):}ToTest {Sub m_sub;....void doo() {Data data = new Data();doo(data, "a");doo(data, "b");doo(data, "c");}void doo(Data data, String val) {data.setValue(val);m_sub.done(data);}}--
You received this message because you are subscribed to the Google Groups "mockito" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Use an argument captor, and check at the end of the tests that the values in it are what you were expecting. So in your case, this might look like this.
@Captor private ArgumentCaptor<Data> captor;...verify(mock, times(3)).done(captor.capture());assertEquals(Arrays.asList(new Data("a"),new Data("b"),new Data("c")), captor.getAllValues());
--
You received this message because you are subscribed to a topic in the Google Groups "mockito" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mockito/w95iWT66Jfo/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
I might be reading too much into what you are writing, but does this mean that you do not own the Sub and Data classes?Because if you do, there must be way to refactor them in order for Sub.done() to take a new Data instance every time, and then wrap it or copy it into a reused instance coming of something else coming from a pool of instances.
If you do not own those classes, maybe this is a sign that you should wrap them with classes you own, à la Growing Object Oriented Software (GOOS).Those new classes might reveal to be so simple they do not need to be unit tested. Or maybe they are easier to test.Contrary to the argument in GOOS, I tend to often refer directly to my external services (ie. classes that I do not control) in my tests. However, issues like the one you describe is a sign that I need to wrap them.
PS: David's suggestion with the argument captor is worth trying, but I agree that it probably stores references, so it will probably not work
On 4 April 2013 08:46, Alexander Broekhuis <a.bro...@gmail.com> wrote:Thanks for your reply,
Op dinsdag 2 april 2013 18:19:27 UTC+2 schreef Eric Lefevre-Ardant het volgende:On 2 April 2013 12:10, Alexander Broekhuis <a.bro...@gmail.com> wrote:
How can I get mockito to record the values, and not only the object reference?
I don't think you can.<snip>This sounds like a case where the tests might force you to make your code more resilient, for example by making your Data objects immutable.While I tend to agree with you, I also think this might be wrong in some cases. For us this is a piece of code which handles hardware messages. For performance reasons it is quite common to use pools for messages. Before sending, retrieve a message from the pool, after sending, return it to the pool.When the message is being sent, the object is actually immutable, but since the sending happens within the unit to test, for the entire unit, the object is cleared and returned to the pool before exiting the method. My use case above was a very simplified version, but that model is also used for performance reasons on restricted devices where object creation is quite expensive...So while the provided example explicitly reuses the object, the problem is still present with pools. The object is returned and cleaned after usage (which is before exiting the method).I'd expect some sort of feature in a testing framework where I can tailor the mock to handle arguments on a custom way. For example by creating a clone instead of simply recording the reference.--You received this message because you are subscribed to the Google Groups "mockito" group.To unsubscribe from this group and stop receiving emails from it, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
--
You received this message because you are subscribed to a topic in the Google Groups "mockito" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mockito/w95iWT66Jfo/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
InOrder inOrder = inOrder(mock); inOrder.verify(mock).done(new Data("a")); inOrder.verify(mock).done(new Data("b")); inOrder.verify(mock).done(new Data("c"));
How about you refactor your code in this way?
It might not seem much, but I believe that it makes it vastly easier to test the ToTest class.Then, testing SubWrapper (ugly name, you'll need to find the right one) is probably a matter of injecting a mock Data instance from your test in a special constructor.What do you think?
Oh, I see. I misunderstood your issue.
What you need to do is to use an Answer object, that copies the arguments, and then run some assertions on it later. Look up Answers in the Mockito documentation; if you can't work it out, then email me and I'll help you more.
Another possibility is to use InOrder.
InOrder inOrder = inOrder(mock); inOrder.verify(mock).done(new Data("a")); inOrder.verify(mock).done(new Data("b")); inOrder.verify(mock).done(new Data("c"));