2

I have inherited a relatively large (~30.000 lines) Python-based project (running on a CAD system for architects) with some messy methods that I have to bugfix at first and go on with the development. These methods place, say, bricks (or stuff like that), into a wall. So most of the code does 3D calculations on coords, vectors, etc.

There are no unit tests for the project currently (and I'm a complete noob for unit testing, I'm a brick-and-mortar architect). Because of the complexity of the functions I have decided to support my work with unit testing, the question is that how can I do it most effectively. Examples I have seen before are much website-based, working mostly on text docs.

The incoming parameters are very complex and large objects, and I use only few of the stored data. Obviously I have to make templates out of it.

There are two possible ways:

  1. To save a real word data as a Python pickle and later use this as a template, and save it to disk.
  2. To set up objects dynamically. Note that used objects' __init__() methods are mostly like this:


class FirstClass:
    def __init__(): 
      self.x = 0
      self.y = 0
      self.fc = self.FirstClass()

class SecondClass:
    def __init__():
        self.blabla = 0

and so on, there are no complicated calculations. Obviously I can put my custom data by overwriting the initialized instance variables like this:

objects.in_the_test_used_data = some_numbers

My question is which is the better method for templates, or whether there is a better approach for this et.

Thx

1 Answer 1

2

Both approaches are valid, but with a small changes.

For the first approach, you can pickle everything, but it might be easier to maintain a json/xml/etc file, if you can do that you can change the data in the future, it will be an easy change, over re-pickling.

For the second approach, you can define your own test-classes/test-instances, but the real solution would be to use a factory library, I personally love factory_boy. It let you define factories for your classes, and help you generate instances easily.

for instance:

class AccountFactory(factory.Factory):
    class Meta:
        model = objects.Account

    username = factory.Sequence(lambda n: 'john%s' % n)
    email = factory.LazyAttribute(lambda o: '%[email protected]' % o.username)
    date_joined = factory.LazyFunction(datetime.datetime.now)

Will let you call AccountFactory() and get an Account object.

Personally, I prefer the second method, it let you be flexible about your data, make changes, easy to read and has a great API. You will also avoid using large files that has to be committed to your version control and won't really be readable.

Sign up to request clarification or add additional context in comments.

2 Comments

Since the object given to the tested function may contain references that can contain infinite referencing (object A -> object B -> object A), I also prefer the second option.The factory stuff is all new to me, thx for sharing the idea.
I won't go into details because this is too board, but check out SubFactory. You can also init a factory with an instance: AccountFactory(profile=ProfileFactory(country=(CountryFactory())))

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.