DEV Community

Joseph Mancuso for Masonite

Posted on • Updated on

Testing Tip: Testing a Controller with a Model in Masonite

Introduction

We're going to keep this one real short. I'll just make this some code snippets and explanations.

Almost 80%+ of the time, we will have some models within our controllers but it's usually hard to mock those models up. For example we might have a controller with some logic like:

from app.User import User

class MikeController:

    def show(self):
        return User.find(1).name # returns Mike
Enter fullscreen mode Exit fullscreen mode

But if we go into our test we have something like:

from app.http.controllers.MikeController import MikeController

class TestController:

    def setup_method(self):
        self.controller = MikeController()

    def test_controller_show_returns_mike(self):
        assert self.controller.show() == 'Mike'
Enter fullscreen mode Exit fullscreen mode

We are not able to mock the User class because it is hard coded into our controller. It will be pulling in directly from the database. What if we wan't our tests to run without even touching the database?

The Solution

We can simply add that user as a class level attribute:

from app.User import User

class MikeController:

    __user__ = User

    def show(self):
        return self.__user__.find(1).name # returns Mike
Enter fullscreen mode Exit fullscreen mode

and then we can mock up that model:

from app.http.controllers.MikeController import MikeController

class MockUser:
    name = 'Mike'

    def find(self, index):
        return self

class TestController:

    def setup_method(self):
        self.controller = MikeController()
        self.__user__ = MockUser()

    def test_controller_show_returns_mike(self):
        assert self.controller.show() == 'Mike'
Enter fullscreen mode Exit fullscreen mode

TADA! We can now throw in any model there inside the self.controller.__user__ attribute and it will be mocked when we test the code. This is a nice little tip for testing controllers. Our controllers might look something like:

from app.User import User
from app.Phone import Phone


class MikeController:

    __user__ = User
    __phone__ = Phone


    def show(self):
        return self.__user__.find(1).name # returns Mike

    def call(self):
        return self.__phone__.where('user_id', self.__user__.find(1).id).first()
Enter fullscreen mode Exit fullscreen mode

This is really testable and a cool little trick.

Top comments (0)