[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [jfw] Re: Private methods should not be unit-tested



Thank you Andrew, for your explanation of mocks. The subject is a bit different from the topic I brought up in this thread, but the connection was made in Karthik's question.
An article that provides some more background on mocks and stubs is: http://martinfowler.com/articles/mocksArentStubs.html
And of course the chapter on Test Doubles in the PHPunit manual: http://phpunit.de/manual/current/en/test-doubles.html

We are all very happy that Sebastien Bergmann (who made PHPunit) will be a keynote speaker on J & Beyond
In http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html  he concludes, after showing how to test a private method using Reflection:

I agree with Dave Thomas and Andy Hunt, who write in their book "Pragmatic Unit Testing":

"In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out."

So: Just because the testing of protected and private attributes and methods is possible does not mean that this is a "good thing".

Maybe the new @uses annotation in PHPunit can be of help here too, to refer to a private method that was tested at a public level:
http://thephp.cc/viewpoints/blog/2014/03/phpunit-4-0-code-coverage-improvements


On Tuesday, 18 March 2014 05:31:44 UTC+1, Andrew Eddie wrote:
On 18 March 2014 14:10, Karthik Narendran <> wrote:
> Alright, rephrasing my question. How exactly does mocks help? Also what is
> the difference between mocks and test helper classes. Bit confused here.

Okay. Pull up a chair and get comfortable :)

So the test helper class is just a shortcut to access protected, and
sometimes private, properties and methods in a class. You can test
public methods easily by invoking them, for example:

$this->assertTrue($instance->publicMethod());

That's easy. However, it doesn't work for protected or private methods
and the helper is just there to save us writing the reflection code
all the time.

Now, mocking. The idea of mocking is to isolate the code you are
testing from code that you are interacting with. If you are, for
example, trying to test methods in an Application level class, it may
rely on database drivers and caching classes and a whole host of
dependencies. But to test a specific method in our application class,
we don't want to be using real database objects, etc. So we mock or
"simulate" their behaviour without actually running the the real code
in these dependencies. In Unit Testing, we are just worried about the
code in our particular class.

Let's imagine we have a class that uses a Cache object. In the repo
you'll see a Mock Helper class:
https://github.com/joomla-framework/cache/blob/master/Tests/Mocker.php
 PHPUnit has good support for mocking and the idea here is to create a
"fake" object to simulate the behaviour of calling `clear`, `exists`
etc and so on. In this way we can inject dummy data into a mock cache
object in order to test our specific class for different use cases
(when a value is in cache, when it's not, etc). We rely on the unit
tests in the Cache package itself to ensure that it works the way it
is intended to.

Here's an example where we "mock" a database object for testing the
AbstractDatabaseModel class
https://github.com/joomla-framework/model/blob/master/Tests/AbstractDatabaseModelTest.php

In that case we only want to test the code in that class and *not* run
the code in the real database class (we actually don't care about that
code at all, we just want to simulate it being used).

There's also the idea of "stubs" and the difference between them and
mocks is subtle. I would generally use a "stub" to test a abstract
class, because you can't instantiate an abstract class directly. That
may or may not be exactly what is meant by "stubbing", but it's how I
think about it. Here's an example of a stub:
https://github.com/joomla-framework/model/blob/master/Tests/Stubs/DatabaseModel.php

It's actually a concrete class whereas a mock is completely simulated.

But there is also integration testing where we do want to use all the
real object to ensure that, when combined, all the pieces actually do
work properly together. In that case, you don't use mocks.

It does, however, take some time to get your head around these
concepts, especially mocking. Even then, I look at tests I wrote years
ago and wonder if I was eating magic mushrooms at the time - some of
them are terrible and don't isolate the code well at all.

Does that help?

Regards,
Andrew Eddie

--
Framework source code: https://github.com/joomla/joomla-framework
Visit http://developer.joomla.org for more information about developing with Joomla!
---
You received this message because you are subscribed to the Google Groups "Joomla! Framework Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-framework+unsubscribe AT googlegroups.com.
Visit this group at http://groups.google.com/group/joomla-dev-framework.