What's the right way of unit-testing a python class?

I'm not sure what's the best way to build independent unit tests on methods of a python class. Here is a trivial example:

class MyClass(object):
  def __init__(self, data):
    self.data = data

  def myMethod(self):
    #do something
    return True

I'm building unit tests like this:

class TestMyClass(unittest.TestCase):
  def test_init(self):
    mydata = mock.Mock()
    c = MyClass(mydata)
    self.assertEqual(c.data, mydata)

  def test_myMethod(self):
    mydata = mock.Mock()
    c = MyClass(mydata)
    self.assertTrue(c.myMethod())

OK, this is very trivial... but the point is: test_myMethod() depends on __init__ because I have to instantiate the object itself: it isn't really isolated. The only way that has come to my mind to solve this issue is mocking the object itself... but how can I test a real method on a mocked object?

I know that in real world a perfect isolation could be impossible, but I'm curious to know if there are better ways.


Asked by: Thomas197 | Posted: 06-12-2021






Answer 1

It comes down to what you want to test and in how much granularity. For example, what exactly is the assertion that c.data equals the data you have just assigned in the previous line actually test? It tests a single line of practical code, and it tests a rather unimportant implementation detail. This is probably much too granular to bother.

You want to ensure that your object behaves as it should overall. That means you want to test that you can instantiate it, and then assert that

  1. if you instantiate it with data A and then call method B the result will be C
  2. if you instantiate it with data D and then call method B the result will be E
  3. if you try to instantiate it with incorrect data that an error is thrown

Your tests should focus on object behaviour, not on testing implementation minutiae. Write your tests so you could drop in an alternative object implementing the same behaviour in a different way without breaking your tests. You are writing that class to get some specified tasks done; test that your implementation can get those tasks done, not how it gets them done.

Exempli gratia:

def test_worksWithDataA(self):
    c = MyClass({'some': 'data'})
    self.assertTrue(c.myMethod())

def test_worksWithDataB(self):
    c = MyClass({'other': 'data'})
    self.assertFalse(c.myMethod())

def test_rejectsDataC(self):
    with self.assertRaises(SomeException):
        MyClass(None)

You only need to mock something if you need to pass a dependency, but that dependency is too complex to instantiate for the sake of the test. As long as your data is just a dict, there's no need to mock it. If your data is a complex type on its own, then you may want to mock it in order to test MyClass, without getting tangled up in having to test that other class at the same time. When mocking, again, mock the expected behaviour of that class; as a rule of thumb, all the behaviour you're asserting your class has using unit tests can be mocked elsewhere.

Answered by: Owen813 | Posted: 07-01-2022



Similar questions

Python, unit-testing and mocking imports

I am in a project where we are starting refactoring some massive code base. One problem that immediately sprang up is that each file imports a lot of other files. How do I in an elegant way mock this in my unit test without having to alter the actual code so I can start to write unit-tests? As an example: The file with the functions I want to test, imports ten other files which is part of our software and not pytho...


Python unit-testing with nose: Making sequential tests

I am just learning how to do unit-testing. I'm on Python / nose / Wing IDE. (The project that I'm writing tests for is a simulations framework, and among other things it lets you run simulations both synchronously and asynchronously, and the results of the simulation should be the same in both.) The thing is, I want some of my tests to use simulat...


python - Unit-testing extensions for an 'external' program with pyunit

I'm struggling to know where to start with unittest, having read the dive-into-python tutorial and looked at http://pyunit.sourceforge.net/. I've got a piece of analysis software (call it 'prog.exe') which uses python for its input decks. I've started writing a python module which I'm going to import from that input deck to provide some useful functionali...


python - Tunnel interface unit-testing

I've made a Tun class that wraps pytun.TunTapDevice : from pytun import TunTapDevice class Tun(object): def __init__(self,name='tun',addr=None,dstaddr=None,netmask=None,mtu=None): tun = TunTapDevice(name=name) if addr : tun.addr = addr if dstaddr : tun.dstaddr = dstaddr if netmask : ...


python - Flask blueprint unit-testing

Is there a good practice to unit-test a flask blueprint? http://flask.pocoo.org/docs/testing/ I didn't found something that helped me or that is simple enough. // Edit Here are my code: # -*- coding: utf-8 -*- import sys import os import unittest import flask sys.path = [os.path.abspath('')] + sys.path from ap...


python - Django unit-testing client.login not working

I am using django 1.6 and I have the following test code: def tes_stuff(self): new_user=EndUser.objects.create(username="test", firstname="test", email="t@t.com", password="test") self.assertTrue(self.client.login(username="test", password="test")) When I run it I get an arror that says: AssertionError: False is not true I am unsure why it is not l...


Is there a preferred BDD style unit-testing framework for Python?

I was wondering if there are any BDD-style 'describe-it' unit-testing frameworks for Python that are maintained and production ready. I have found describe, but it doesn't seem to be maintained and has no documentation. I've also found sure which reached 1.0, but it seems to just add syntactic sugar i...


Python Unit-Testing All Test Cases

I am running unit tests on pycharm but some how am discovering something weird. When I started testing a class, more specifically its methods, I simply wrote test cases like the following: # hey.py class hey: def hello(self): return True def bye(self): return 'Bye' # test_hey.py from unittest import TestCase class TestHey(TestCase): def test_hello(self): self.fail() ...


python - Unit-Testing Flask application views & dialogs

I am new to Flask and have recently started working on a project. After I've fixed some issues related to dialogs and views the client asked to write unittests to verify the resolutions. I've gone through some already written tests but they mostly just check the status code of http response, like this: def test_home_page(self): rv = self.client.get('/home') self.assertEqual(rv._status_code, 200, rv....


django - Unit-testing Python: Mocking function calls inside function

I have a django view like this # Django view from some_module import f2 def f1(request, version): # some code f2(**kargs) # more code return HTTPResponse(response) The function f2 is in another module # some_module def f2(**kargs): # some code The Django view is part of an API so, the request and response are in json How do I...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top