how do you provide deep mock objects?
I don't think I understand testing as well a should. I have written a lot of tests and gotten decent coverage but I cann开发者_如何学JAVAot help feeling it has not been intuitive.
Let me explain: if I have a class the I am testing a method and it needs to be passed a big object of some sort, with all kinds of state. This object in turn contains other objects and their states that I know nothing of, how do I create mock or stub objects for this method and give it data that it can work with. It seems I have to create a big object with all kinds of internal sub object information to exercise my method. I'm clearly confused!
The other answers here are pointing you to mocking frameworks, which you should definitely look at if you're not already using (use Mockito!). However, this is almost certainly an instance of your tests telling you that you've got design problems. If you find yourself having to provide all kinds of unrelated information and mock objects just to make a test pass, then you're
- trying to test too many pieces at once,
- writing a test that will be very difficult to read and understand when you're done with it because it's impossible to determine what the test is supposed to be focused on due to a low signal/noise ratio, and/or
- writing an extremely fragile test that will break on the slightest, unrelated change, incurring high maintenance costs and a "just make the test pass" mentality that doesn't care what the test is supposed to be testing.
These are all symptoms of a system not designed for testability, which almost universally equates to a system not designed for readability, meaning it's not designed well.
If you care about testing well, embrace test-first thinking and TDD. I highly recommend a couple of books on the subject: "xUnit Test Patterns", which I've read and reviewed, and "Growing Object-Oriented Software, Guided by Tests", which I'm almost finished reading.
What you want is a mocking framework. There are many of them. Have a look at either Mockito or EasyMock.
In short, you would use code that looks like this:
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
Which allows you to specify the behavior when a particular method is called without needing to mock up the entire object. If you have a very complex object, you are mocking, it will be a little more complicated, but you basically just specify the behavior that you are expecting to see used.
One way to deal with an object with a lot of state and dependent objects that you don't care about it to use a 'nice mock' in EasyMock (the default in Mockito I think). This will always return 'empty' values for any method on your mock object (null, 0 or empty string).
If the dependent objects need to do something then you'll need to return actual or mock objects from your object.
For example, in EasyMock, it will look something like:
Mock mock = createNiceMock(MyClass.class);
// override default 'empty' returns for values you care about
// this could return a mock instead
ChildObj c = new ChildObj("state");
expect(mock.getChildObj()).andReturn(c);
// replay, call methods on object under test, verify here
But, you probably want to start with the bigger picture: why are you using mocks? Some people prefer testing only with real objects and stubs, while others prefer mocks. Googling 'mocks v. stubs' and reading the top 3 or 4 results will help you decide if mocks are right for you.
As you didn't mentioned the mocking lib you are using, I shall suggest what I am using.
However, I haven't tried this feature yet, because it smells bad to me. Just see if it is really unavoidable:
In Mockito, you may have a deep stub when creating mock: Example in official site
精彩评论