41

Half way through my current project, after suffering the pain of spending uncountable minutes on debugging, I have decided to adopt TDD. To start, I am planning to write a set of unit tests for each existing models. But for models that only have attributes defined (ie. no additional methods/properties) I am not sure what I need to test nor how.

class Product(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField(default='', blank=True)
    retails = models.ManyToManyField(Retail, verbose_name='Retail stores that carry the product')
    manufacturer = models.ForeignKey(Manufacturer, related_name='products')
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

Using Product as an example, what are the things about it that unit tests should cover? And how should ForeignKey and ManyToManyField be covered?

tamakisquare
  • 15,251
  • 24
  • 79
  • 125

2 Answers2

84

This was an article I found helpful: A Guide to Testing in Django (archived link). Here is a good summary of what to test:

Another common setback for developers/designers new to testing is the question of 'what should (or shouldn't) I test?' While there are no hard & fast rules here that neatly apply everywhere, there are some general guidelines I can offer on making the decision:

  • If the code in question is a built-in Python function/library, don't test it. Examples like the datetime library.

  • If the code in question is built into Django, don't test it. Examples like the fields on a Model or testing how the built-in template.Node renders included tags.

  • If your model has custom methods, you should test that, usually with unit tests.

  • Same goes for custom views, forms, template tags, context processors, middleware, management commands, etc. If you implemented the business logic, you should test your aspects of the code.

So, for your example, there wouldn't really be anything to test until you write some custom functions.
In my opinion, testing ForeignKey and ManyToManyField links would fall under the second category (code built into Django), so I wouldn't test these, as you are really testing whether or not Django is functioning properly. If you have a method which creates an instance of your product, including foreign relationships and M2Ms, you could verify the data has been created, that would be testing your custom method, not Django functionality.

Using the TDD paradigm, the tests are built to verify business logic, and design requirements.

culix
  • 8,979
  • 5
  • 31
  • 49
Furbeenator
  • 7,322
  • 4
  • 40
  • 51
  • 3
    Yea, it really helped me out. I think testing is one of the biggest parts of development that often gets overlooked due to time constraints. This is also why writing efficient, effective, and non-redundant tests is so important. Happy Testing! :-) – Furbeenator Mar 06 '12 at 16:07
  • @Furbeenator my colleague says that we should test `auto_add` fields, because someone might change it in future and/or remove it. Is she right? – Masious Nov 24 '15 at 13:51
  • Hi @Masious, I'm not sure I understand the context. What will you be testing for this field? The main point is you want to test code that you've written, not code that is native in the framework - they've already done that for you. If you have a function that changes a record and you want to see if the auto_add has performed as expected, that seems redundant, but without the context it is hard to tell. You only need to unit test for things your code is supposed to change. The data set is all going to be created within your unit testing, so you shouldn't have to worry about external changes. – Furbeenator Nov 25 '15 at 01:18
  • 1
    Hi, the link that you provided is not a valid link. – Arshad May 04 '18 at 10:08
  • 1
    you save me tons of hours. Cheers. – Elias Prado Jun 22 '20 at 16:20
  • That link is no longer good, but I think the summary you present is partially mistaken. The way we *configure* a model is prone to bugs and errors, so we need to test fields. We need to know that we have a FK to the correct model, we need to know that we have the correct `max_length` on a CharField. This isn't testing Django, this is testing our own code that Django happens to give us a shorter way of writing. – Dustin Wyatt Jan 14 '21 at 19:43
  • Thank you, Dustin. The point was really that you shouldn't duplicate tests for functionality built and tested by Django. Yes, the last sentence addresses the issue you raise, your tests should be built to "verify business logic and design requirements" but not to verify Django's code is working properly. – Furbeenator Jan 22 '21 at 18:30
  • 1
    There is an archived copy of the article available here - https://web.archive.org/web/20110413151745/http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/ I can add this link into the answer – culix Jan 27 '21 at 17:52
  • Thanks, @culix. – Furbeenator Jan 28 '21 at 18:17
0

My CS350 class TDD stipulated that it's best practice to test all accessors and mutators. So for a model, you would first write tests that call each assessor function and make sure that it returns the proper value.

For each function which changes a data field in the model, you would not only test the result of that data field in particular, but you would also test all of the other fields in the model instance to make sure that none of them were modified erroneously.

To restat:, if a model has fields a, b, and c, you would create an instance using your constructor, then asset that all three are set properly. Say there's another function, set_a(). You would assert that not only the value of 'a' has changed, but that the values of b and c remain unchanged.

dahifi
  • 47
  • 1
  • 5