1

I came across this term when looking into PHP's "traits" (which are apparently bad, since, among things, they're not mockable), but I can't really find a definition for this "mockability". It might be related to polymorphism? There isn't even a Wikipedia entry I could find!

  • 1
    I googled "mock oop" and the very first result is a link to Wikipedia's article on mock objects: en.wikipedia.org/wiki/Mock_object – Tulains Córdova Apr 25 '14 at 16:04
  • That's quite a different query from "mockable" now, isn't it. – Protector one Apr 26 '14 at 17:36
  • You can infer "mockable" means that can be mocked. So reading the Wikipedia article about what mocking is in the context of OOP pretty much answers your question about what is a mockable object. – Tulains Córdova Apr 26 '14 at 20:12
3

In order for something to be called mockable, you must be able to replace its implementation with another implementation within the context of a unit test, without affecting the code used during normal runtime. This is used to make the testing easier, by not pulling in a ton of dependencies or performing resource-intensive operations.

There are a number of fallacies in that article. First of all, when you use a trait, you should think of it as copying and pasting the trait's code into your class. The trait's code becomes part of the class, and therefore part of the unit you are testing. The complaint that traits aren't mockable is a little ridiculous. It's like complaining that base classes aren't mockable.

If a trait doesn't make sense as part of the unit, it shouldn't be a trait. You should use another means to share the functionality, like inheritance or composition. Like any other language feature, there are good and bad situations in which to use traits.

Second, traits are mockable, although not as easily. You should generally avoid it, just like you would generally avoid mocking any other method of the class you're testing. For example:

trait MyTrait {
    public function traitFunction() {
        expensiveDatabaseCall();
    }
}

class MyClass {
    use MyTrait;
}

To mock the trait, use something like the following in your unit test:

trait MockTrait {
    public function traitFunction() {
        echo "don't have to make a database call";
    }
}

class TestMyClass extends MyClass {
    use MockTrait;
}

This is a variant of the "subclass and override" technique Michael Feathers details in his book Working Effectively with Legacy Code.

Again, the technique is not the first choice for unit testing, but it will do in a pinch. The preference would be to mock expensiveDatabaseCall().

Mock objects are usually passed in as an argument to a constructor or a method. You can't pass a trait as an argument, which I suspect is why the author of that article called them not mockable, but it's far from the case that traits prevent you from effectively unit testing a class, even if you don't mock them.

In fact, using traits properly can simplify your code, making it easier to unit test. They reduce boilerplate and reduce the "plumbing" code that only exists to connect up other classes that do the real work.

6

Huh. I found this after looking at stackexchange's description of the "mocking" tag. Since you, reader, might be like me, check this out: http://en.wikipedia.org/wiki/Mock_object

In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior of a human in vehicle impacts.

3

The use of mock objects in unit testing is fairly commonplace. Mock objects are, as you've said, controlled objects that mimic behavior of some other objects you don't want to touch. A good example would be a method that writes something in the database - instead of using actual database records, you are far better off using mock objects to mimic the database adapter and provide mock result sets, in order not to touch the database at all (if you're inserting into a database, at the end of the test you would need to alter the tables back to their initial form, but if you stop the test mid-process the database would remain affected by the test and you would get inconsistencies, other units might be affected further down the road in the test case so it would break the context of unit testing and so on).

The problem with traits not being mockable is that they are not concrete objects - in the inheritance chain they sit somewhere between the child and the parent, out of your control through the unit testing framework (without altering the actual code of the application to provide specific functionality, which I don't think I need to say it's utterly pointless). A somewhat distant analogy would be to the decorator design pattern, where particular objects are augmented at runtime with various other injected behavior which can differ from the implementation of the original class - but in the case of decorators, you know what to expect and can destroy the context after each unit is executed.

Because a trait can alter the objects's context (calling a method implemented in the trait that does database operations, for example, or having a trait that overrides an internal class variable from the parent class, that's not controlled in the child class), you can get unexpected behavior which can exist outside the scope of unit testing and which you cannot control using a mock. To continue the analogy with the crash test, you would have a crash test dummy that can pull the parking brake or unbuckle its seat-belt without you being able to control that part of the behavior.

1

You can find people writing books more or less alone on this subject (alongside concepts like "stub", "spy", "fake" or "dummy"). Puritans (pardon the possible insult to some people here) will argue on the suttle differences between e.g. mocks and stubs (see e.g. Martin Fowlers exellent article http://martinfowler.com/articles/mocksArentStubs.html).

My 5 cents would argue that a mock is an object mimicking the behaviour of a dependent object of the object being tested. You can make the mock return expected values or you can check that certain attributes / properties or methods are being called as part of the test. Being mockable then, somehow infers having substitutuable behaviour, either through an interface or otherwise. This enables the mock object to record and replace the behaviour.

I've come to find that for my (.NET) testing purposes a library like NSubstitute (http://nsubstitute.github.io/) is just right. One of the driving ideas is (quote): "Mock, stub, fake, spy, test double? Strict or loose? Nah, just substitute for the type you need!"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.