2

I am facing a problem where i run tests when i just need them as simple methods. for example in test_add_waiter i must first register a user with self.test_register_user(). I do this so i wont repeat code (the register_user method works perfectly and i copied it from the actual test class). But the test (test_register_user) runs as a test and i do not want to test it but use it as a method. What do you propose i do? Is there a way to ignore it in the init of the class. Or am i over thinking this. The are many test classes that i have to face this exact issue.

Example Code

#./tests/test_basics.py

import os
import unittest
from flask import current_app
from app import create_app
from app import db


class BasicsTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app('testing')
        self.app_context = self.app.app_context()
        self.app_context.push()
        self.client = self.app.test_client()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        os.remove('../test.db')
        self.app_context.pop()

    def test_app_exists(self):
        self.assertFalse(current_app is None)

    def test_app_is_testing(self):
        self.assertTrue(current_app.config['TESTING'])

#./tests/application/test_api_app_menu.py

import json
from flask import url_for

from tests.fake_data import create_random_waiter_item
from ..test_basics import BasicsTestCase

class MenuTestCase(BasicsTestCase):

    def test_register_user(self):
        # http://stackoverflow.com/questions/28836893/how-to-send-requests-with-jsons-in-unit-tests
        res = self.client.post(url_for('/auth.authentication'), data=json.dumps({"email": "test@gmail.com",
                                                                                 "username": "test",
                                                                                 "password": "123456"}),
                               content_type='application/json')
        return self.assertTrue(res.status_code == 200)

    def test_register_user_id(self):
        # http://stackoverflow.com/questions/28836893/how-to-send-requests-with-jsons-in-unit-tests
        res = self.client.post(url_for('/auth.authentication'),
                               data=json.dumps({"email": "test@gmail.com",
                                                "username": "test",
                                                "password": "123456"}),
                               content_type='application/json')

        data = json.loads(res.data)

        self.assertTrue(data["user_id"] == 1)

    def test_add_waiter(self):
        # register user in order to register a store.
        self.test_register_user()

        sample_item = {"items": create_random_waiter_item()[0]}

        res = self.client.post(url_for('/manage.waiter')+"?store_id=1", data=json.dumps(sample_item),
                               content_type='application/json')

        # data = json.loads(res.data)
        self.assertTrue(res.status_code == 201)

    # Todo 19/3/2017 - fix the unique constraint error  wher registered user is ran along with register user

    def test_get_menu(self):
        # register user in order to register a store.
        # self.test_register_user()
        self.test_add_waiter()

        res = self.client.get(url_for('/app.menu')+"?store_id=1&cell_phone=1234567890&pin_number=1234",
                              content_type='application/json')
        self.assertTrue(res.status_code == 200)

    def test_get_menu_bad_url(self):
        # register user in order to register a store.
        self.test_add_waiter()

        res = self.client.get(url_for('/app.menu')+"?store_id=&cell_phone=6900000000&pin_number=123456",
                              content_type='application/json')
        self.assertTrue(res.status_code == 400)
George Pamfilis
  • 1,397
  • 2
  • 19
  • 37

1 Answers1

2

I think you may be over thinking it. If it's a fixture/utility method you could name it something else and then not have to worry about the test suite executing it.


I've recently been hooked on DAMP tests. I first read about them in jay fields amazing book Working effectively with unit tests. Jay fields argues that repeating the client post logic for each of your tests helps with maintainability in the long run, at the expense of duplication.

Currently the code you posted is extremely simple. The concept of a user is very straightforward and takes 1 line to create. In my experiences when there are shared fixture methods, the concept of a user changes. Some tests need a barebones user, other tests need to specify a username, or an age, or a permission. This starts to create a frankenstein test method that needs to accommodate every single test, and gets really complicated.

Jay fields recommends having each individual test provision all the data it needs to run, which:

  • creates only the absolutely necessary data to exercise the System Under Test
  • Isolates all data create to the test method, so that when a test fails you only need to look at the failing tests code, and don't have to follow method calls (makes a big difference for a huge code base where you many not have an intimate knowledge of every single line of code, IMO)

This comes at the expense of having every single test create its own data. If the domain model significantly shifts, ie if you don't need users any more but need Entities (or something) it will require you to touch almost all the tests.

But In my experiences, having focused tests that don't delegate, is a net time saver and complexity saver vs the rare times the domain model shifts enough to have to touch all the tests

dm03514
  • 54,664
  • 18
  • 108
  • 145