From: Steve F. <st...@m3...> - 2002-11-17 10:51:11
|
Thanks for your proposal in another message. You might also consider combining the dynamic mock with a hand-rolled mock using the ExpectationSet, e.g. public void MockFoo extends Mock { ExpectationSet values = new ExpectationSet("values); public void addValue(Value aValue) { // override values.addActual(aValue); } public void verify() { super.verify(); values.verify(); } } The hand-coded addValue() method will be picked up before the dynamic implementation. S. Barry Kaplan wrote: > I'm trying to test methods that create sums by invoking other methods. I > can setup the other methods correctly, but the setup of the mock method > calls is always sensitive to the order in which they are called. For the > method under test, this is not a requirement. Is there any mechanism for > setting up a CallSequence to not care about the order, but still ensure > that the total number of calls were made and the parameters were > correct. (I suppose it might have to give each method a shot, and only > fail if all fail to verify?) |
From: Steve F. <st...@m3...> - 2002-11-18 00:21:34
|
Barry Kaplan wrote: > Steve Freeman wrote: > I'm still a bit confused. Consider: > > public void class QuantityHolder { > public int getQuantity(Key key1, Key key1); > } > > public int sum(QuantityHolder holder) { > int result = holder.getQuantity("key1", "key2") + > holder.getQuantity("key3", "key4") + ...; > } > > I want to mock QuantityHolder. I want to ensure that sum() invoked the > getQuantity method twice, with the correct keys, but in any order. depends on quite what you want to test, for example: ExpectationSet keys; public int getQuantity(Key key1, Key key2) { keys.addActual(key1); keys.addActual(key2); } would test that all four keys were used, but not the combinations. In practice, would that satisfy you that you'd covered the bases? alternatively, how about a constraint: P.or( P.and(P.eq("key1"), P.eq("key2")), P.and(P.eq("key3"), P.eq("key4"))); which tests that only the right combinations are passed through. If the arguments are always in the same order, you could try: ExpectationSet keys; public int getQuantity(Key key1, Key key2) { keys.addActual(key1 + key2); } Finally, if the arguments can come in any order but the pairs matter, I think you could try: ExpectationSet keys; public int getQuantity(Key key1, Key key2) { Set keySet = new HashSet(); keySet.add(key1); keySet.add(key2); keys.addActual(keySet); } > I don't see how the ExpectationSet can do this. How to specify the mock > return value for each key1/key2 combination? Can I use the Constraints > with ExpectationSet (for mulitple arguments)? We're still thinking about this one, but it's an obvious direction to go. > > -bk > > BTW, are there any other examples floating around (ie, projects that > make extensive use of mockobjects)? The ones the distribution are ok, > but not too extensive. not sure, but you could contribute some... S. |
From: Barry K. <bk...@in...> - 2002-11-18 15:13:00
|
> > >> I don't see how the ExpectationSet can do this. How to specify the >> mock return value for each key1/key2 combination? Can I use the >> Constraints with ExpectationSet (for mulitple arguments)? > > > We're still thinking about this one, but it's an obvious direction to go. Seems that the dynamic mocksobjects handle this quite nicely. Here's what I did: The class I needed to test was an abstract class, so I could not use Mock or MockObject directly. Instead I mocked just the abstract hook methods required to the test the template methods. In the case of the 'getQuantity' hook method, I did: private CallSet expectedGetQuantity1 = new CallSet(); // Just to provide an easier setup mechansim than having the test use the CallSet directly public void expectGetQuantity(Foo foo, Bar bar, Integer returnValue) { expectedGetQuantity1.expectReturn( new Constraint[]{P.eq(foo), P.eq(bar)}, returnValue); } public int getQuantity(Foo foo, Bar bar) { try return ((Integer) expectedGetQuantity1.call(new Object[]{foo, bar})).intValue(); } catch (Throwable t) { // It kinda sucks that call() declares Throwable. Its really unecessary, since reflection will // throw the exception of the reflected. If the reflected method declares an exception // the mock method can pass it thru (or extract it from the exception the method.invoke() throws). throw new RuntimeException(t); } } public void verify() throws AssertionFailedError { expectedGetQuantity1.verify(); ... } >> >> BTW, are there any other examples floating around (ie, projects that >> make extensive use of mockobjects)? The ones the distribution are ok, >> but not too extensive. > > > not sure, but you could contribute some Well, we have over 3000 unit tests for our system. I looked at mockobjects when we started, but instead decided to use the following very simple mock idiom (aka simplemock): interface: public int getFoo(Bar bar); mock: public boolean getFooCalled; public Integer getFooReturn; public Bar getFooBar; public int getFoo(Bar bar) { getFooCalled = true; getFooBar = bar; return getFooReturn.intValue(); } We have a code generator that creates this simple idiom from interfaces. One of the big problem we ran into with mockobjects was the ability to get back the values passed into mocks (vs. just having the mock assert the values). For example, when testing a class that registers as a listener [with some mock], we often want to get hold of that listener instance (which may be the CUT or an inner of class of the CUT) and invoke methods on the listener so as to test the listening behavior. Implementations of Expectation all maintain the expected values as private and provide no accessors, making this type of usage impossible. On the other hand, testing multiple calls to the mock within a single test using simplemock is painful. You have to explicity code in support. eg, Provide a collection for each argument and return values, or create a custom MockCall abstraction. Back then I never really dug into the mockobjects code. Now, after having done so, I see that the mockobjects implementation is clean and simple, and most of limitations [for us] can easiliy be removed. We used easymock for a while, but had same issues as with mockobjects. As for contributing. I certainly will. Both to the core and dynamic modules, and examples as we incrementally convert. Thanks for the help Steve. -bk (I notice that all your responses post to both user and dev. Should that be the normal practice?) |
From: Steve F. <st...@m3...> - 2002-11-25 00:15:44
|
Barry Kaplan wrote: > One of the big problem we ran into with mockobjects was the ability to > get back the values passed into mocks (vs. just having the mock assert > the values). For example, when testing a class that registers as a > listener [with some mock], we often want to get hold of that listener > instance (which may be the CUT or an inner of class of the CUT) and > invoke methods on the listener so as to test the listening behavior. > Implementations of Expectation all maintain the expected values as > private and provide no accessors, making this type of usage impossible. We probably should open up the instance variables, but we tend to use those forces to push the way we code. I don't really understand your example, could you post a snippet? > Back then I never really dug into the mockobjects code. Now, after > having done so, I see that the mockobjects implementation is clean and > simple, and most of limitations [for us] can easiliy be removed. We used > easymock for a while, but had same issues as with mockobjects. If you have time, could you describe them? > Thanks for the help Steve. my pleasure. > (I notice that all your responses post to both user and dev. Should that > be the normal practice?) not sure who's interested in this, so I'm resorting to a scattergun. Anyone prefer me not to? S. |
From: Steve F. <st...@m3...> - 2002-11-25 00:22:00
|
Barry Kaplan wrote: > Seems that the dynamic mocksobjects handle this quite nicely. Here's > what I did: The class I needed to test was an abstract class, so I could > not use Mock or MockObject directly. Instead I mocked just the abstract > hook methods required to the test the template methods. In the case of > the 'getQuantity' hook method, I did: > > private CallSet expectedGetQuantity1 = new CallSet(); > > // Just to provide an easier setup mechansim than having the test use > the CallSet directly > public void expectGetQuantity(Foo foo, Bar bar, Integer returnValue) { > expectedGetQuantity1.expectReturn( > new Constraint[]{P.eq(foo), P.eq(bar)}, returnValue); > } > > public int getQuantity(Foo foo, Bar bar) { > try > return ((Integer) expectedGetQuantity1.call(new Object[]{foo, > bar})).intValue(); > } catch (Throwable t) { > // It kinda sucks that call() declares Throwable. Its really > unecessary, since reflection will > // throw the exception of the reflected. If the reflected > method declares an exception > // the mock method can pass it thru (or extract it from the > exception the method.invoke() throws). > throw new RuntimeException(t); > } > } > > public void verify() throws AssertionFailedError { > expectedGetQuantity1.verify(); > ... > } For an equality test, I would have done something like: ExpectationValue foo = new ExpectationValue("foo"); ExpectationValue bar = new ExpectationValue("bar"); int quantity; public int getQuantity(Foo aFoo, Bar aBar) { foo.setActual(aFoo); bar.setActual(aBar); return quantity; } public void verify() { Verifier.verifyObject(this); } which I find more obvious. I might take shortcuts, like using an ExpectationList for all the parameters and, these days, I tend not to make the mock fields private and just call setExpected() on them directly. If you get the names right, it's pretty readable. S. |