• Home
  • Making your first Test

Making your first Test

0 comments

So You decided that it’s time to start doing TDD. Everyone is talking about it, everyone is recommending it. But now the difficult part comes in. You have a task to make a website. How to write your first test?

Well first of all, we have to acknowledge that we are not gonna test the content of the page. That is what acceptance tests are for. We are only gonna test small units of logic that leads to it being displayed, in other words we are going to write unit tests.

Let’s begin.

As this is website we are gonna have a post entity.

We write a test that check if we have a post defined:

class TestPost extends \PHPUnit_Framework_TestCase
{
    public function testPostClassExists()
    {
        $post = new Post();
        $this->assertInstanceOf(Post::class, $post);
    }
}

That’s it. Rule in a TDD development is to write enough of a test to make it fail. Checking if Post exist is going to make it red. So now we have to write actual website code that is going to make this test pass. So we create a Post Model.

class Post
{

}

And the test is green.

Next, post should return a specific title, body and author if we give the id of post as a parameter in the method.

We are going to speed up the process a little and also introduce mock-ups. I am going to explain to you this in a moment. Let’s first write a test that covers this scenario.

public function testIfPostCallsGetById()
{
    $post = new Post();
    $singlePost = $post->getById(1);
    $this->assertEquals('My First Title', $singlePost['title']);
    $this->assertEquals('My First Content', $singlePost['body']);
}

Here we are testing that post have getById method that receives an id as parameter and is going to return array of data. Ok let’s make this test pass.

public function getById($id)
{
    return [
        'title' => 'My First Title',
        'body' => 'My First Content'
    ];
}

You must be asking what is wrong with you. These is just hard coded values. Well that is the thing about TDD. You write enough code just so you pass the test. This is the simple possible thing we could have written to have the test pass.

But now we are going to take it up the notch a little. Of course this can’t stay hard coded like this. We are going to have a PostRepository class that is going to have a method getSingleFromDB. It’s going to communicate with database directly and SQL queries are gonna be main responsibility of this class.

Therefore we are going to introduce mock-ups.

What are the mock-ups?

First rule of test is that, after the test if finished executing, there should never be leftovers. Executing SQL is going to leave leftovers. Also we have to remember that we are testing business logic here, not database. Database should be separated from our logic.

Keeping that in mind we are not going to try and communicate with database, but we are going to fake it. That is where mock-ups come into play.

So getById method should initialize PostRepository class and call it’s getSingleFromDB method which should return the same array we currently have.

We are deleting the testPostClassExists test we have, because well we don’t need to check if Post is defined anymore and we are going to refactor testIfPostCallsGetById and rename it to testIfPostRepoIsCalled.

public function testIfPostRepoIsCalled()
{
    $postRepoMockup = $this->getMockBuilder(PostRepository::class)
        ->setMethods(['getSingleFromDB'])
        ->getMock();
    $postRepoMockup->expects($this->once())->method('getSingleFromDB')
        ->willReturn([
            'title' => 'My First Title',
            'body' => 'My First Content'
        ]);
    $post = new Post($postRepoMockup);

    $expected = [
        'title' => 'My First Title',
        'body' => 'My First Content'
    ];
    $this->assertEquals($expected, $post->getById(1));
}

What have we done here?

First we get Mock of a PostRepository class and we set that getSingleFromDB method is something we don’t want to be called by original class but by our mock-up.

Then we say that we want that method to return array that we have previously seen. You could say this is the same as before, we are hard coding the result. But that is not the test here. The real test here is that we are just making sure that this method getSingleFromDB is called and that it’s called only once. Because this is Post class test, not a PostRepository Test. We are going to do that separately. Post responsibility is to call PostRepository’s getSingleFromDB method only and we are here to make sure that happens.

We changed a couple of things here. We introduced a construct method for Post and well we have to create PostRepository class also.

Let’s make this test pass.

class Post
{
    private $postRepo;

    public function __construct(PostRepository $postRepo)
    {
        $this->postRepo = $postRepo;
    }

    public function getById($id)
    {
        return $this->postRepo->getSingleFromDB($id);
    }
}

As I said getById method only calls getSingleFromDB, it doesn’t check it’s logic. This is the reason why TDD makes you split responsibilities and make your code cleaner.

So You decide that you are not gonna use MySql or PostgreSql and maybe try MongoDB. Only thing you have to change is PostRepository class. Everything else is going to stay the same.

Now finally lets make PostRepository class which is going to be a dummy class for now.

class PostRepository
{
    public function getSingleFromDB($id)
    {
        // SQL QUERY TO DB
    }
}

With this we have a passing test with 100% of code coverage.

Next time I am going to show You how to test Controllers which will comunicate with Post Model and send data to views.

 

About the Author

Follow me

30 year old software developer from Mostar, Bosnia and Herzegovina, currently living and working in Frankfurt am Main, Germany.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}