I’m trying to return an object when mocking a parser class. This is the test code using PHPUnit 3.7
//set up the result object that I want to be returned from the call to parse method
$parserResult= new ParserResult();
$parserResult->setSegment('some string');
//set up the stub Parser object
$stubParser=$this->getMock('Parser');
$stubParser->expects($this->any())
->method('parse')
->will($this->returnValue($parserResult));
//injecting the stub to my client class
$fileWriter= new FileWriter($stubParser);
$output=$fileWriter->writeStringToFile();
Inside my writeStringToFile()
method I’m using $parserResult
like this:
writeStringToFile(){
//Some code...
$parserResult=$parser->parse();
$segment=$parserResult->getSegment();//that's why I set the segment in the test.
}
Should I mock ParserResult
in the first place, so that the mock returns a mock?
Is it good design for mocks to return mocks?
Is there a better approach to do this all?!
In general having a chain of mocks returning other mocks is considered a code smell in tests.
That being said, the answer of whether this is good idea is of course “it depends”.
About your ParserResult object – if it is a small value object then constructing it and passing it in is probably a good idea.
If it is a large object with dependancies of its own, then mocking it would be a better option. Not mocking it would increase the coupling in your tests.
Another question to ask about the design is what is the result of ParserResult.getSegment used for? Perhaps a Tell Don’t Ask style might be better, can you tell ParserResult or Parser to do something with the segment information instead of extracting it and then operating on it?
2
I think it’s a good idea to mock the smallest and closest possible set of dependencies to the class you are testing.
The idea is to reduce the test into the simplest possible scenario so it’s easy to ensure the test is correct and that only tests one thing.
If you return a mock you are testing two separate things, the function that consumes the mock and the class that now creates and returns the mock.
So test the consumer and the producer of the ParserResult separately.