I
I
itcoder2015-09-24 16:48:05
PHP
itcoder, 2015-09-24 16:48:05

How do you write testable code?

Essence of the question: If you do not rely on any framework, but take as a basis a simple implementation of MVC, without dependency injection.
For example, you need to test the prepareBuy method in the User model,
but when testing the method, you can see that the order->paid($userId) method is called inside,
which refers to an external source that cannot be pulled. accordingly, when testing, you need to wrap it in Mock:

class MockTest extends PHPUnit_Framework_TestCase
{
    public function testUserPay()
    {
        $order = $this->getMock('Order', ['paid']);

        $order->expects($this->once())
            ->method('paid')
            ->will($this->returnValue('ok'));

        $subject = new User;
        $subject->attach($order);

        $this->assertEquals('ok', $subject->prepareBuy(999));
    }

class User
{
    protected $order = null;

    public function attach(Order $order)
    {
        $this->order = $order;
    }

    public function prepareBuy($userId)
    {
        return $this->order->paid($userId);

    }
}

class Order
{
    public function paid($argument)
    {
        return $argument;
    }

}

Actually a question: How it is better to write the code for such tests?
Write a constructor in each model? to which to transfer instances of classes, and if there are many sources: you will have to call in the code, for example:
$user = new User()->attach(new Order);
$user->prepareBuy(999);

which is not very convenient.
Pass object as method parameter?
For example, if via late static binding to, don't do new
User::model()->prepareBuy(new Order, New Profile, $userId)

but if you need to call the method many times, it becomes inconvenient to write the parameters again.
I want to hear advice on how you solve this problem?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
A
Alexey Ukolov, 2015-09-24
@alexey-m-ukolov

To solve this problem, they came up with Dependency Injection and the IoC container.

S
Sergey, 2015-09-24
Protko @Fesor

accordingly, when testing, you need to wrap it in Mock

Well, as it would be logical, when unit testing everything, except for what we are directly testing, should be replaced by a mock / stub.
What do you understand by "model"? Your business objects? They should only have what they need in their constructor.
That is a reason to reconsider the architecture, read about the chain of responsibilities, strategies, about the segregation of interfaces in the end.
Read this line of code and tell me what's going on here because I can't figure it out.
Well, yes, in addition to dependency injection in the constructor, there is also such a good thing as double dispatch, when the necessary services are passed as arguments to the methods that need them. So our class does not depend on incomprehensible things, and thus we can safely test everything.

M
matperez, 2015-09-24
@matperez

Read the book The Clean Architecture in PHP . There and about architecture and about tests is.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question