classification
Title: Add method to mark unittest.TestCases as "do not run".
Type: enhancement Stage: needs patch
Components: Library (Lib) Versions: Python 3.3
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: michael.foord Nosy List: eric.araujo, kristjan.jonsson, michael.foord, pitrou, r.david.murray, stutzbach
Priority: normal Keywords: easy

Created on 2012-04-09 13:10 by r.david.murray, last changed 2012-04-14 10:34 by kristjan.jonsson.

Messages (11)
msg157842 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-04-09 13:10
A common pattern in testing is to have a base test class that implements test methods, and subclasses that provide various data that drives the tests to be run in different ways.  It is convenient for the base class to inherit from TestCase, but this causes the normal test loader to load it as a test to be run, when most times it can't run by itself.

My proposed solution is to make test case loading depend on an attribute of the class rather than the fact that it subclasses TestCase.  TestCase would then have the attribute set to True by default.  A decorator would be provided that sets the attribute to False, since that would make it visually obvious which TestCases are base classes and not to be loaded.

(Note: once this is available the 'best practices' description of test file construction in the documentation for the stdlib 'test' module should be updated to use it.)
msg157867 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-04-09 17:24
> A decorator would be provided that sets the attribute to False, since
> that would make it visually obvious which TestCases are base classes
> and not to be loaded.

What's the point? Just derive from TestCase in the derived classes, not the base classes.
-1 on useless complication.
msg157868 - (view) Author: Daniel Stutzbach (stutzbach) (Python committer) Date: 2012-04-09 17:45
Wouldn't the subclass inherit the False value?  Then the user would need to remember to override the value again in the subclass, which is error prone.

Antoine: I've used the pattern you describe on a couple of occasions, and it routinely confuses my code reviewers.
msg157869 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-04-09 17:50
Antoine: I don't have any problem with that personally, but Michael did, and he's the maintainer :)

But there is a small advantage: it means you don't have to keep repeating the 'unittest.TestCase' boilerplate in each subclass declaration, you only have to decorate the base class once.

Daniel:  Oops, you are right. Michael seemed to have some idea on how to implement the decorator.  The class attribute was my contribution, and obviously that isn't going to work.  I wanted something more transparent than a magic decorator, but it looks like magic will be required.

Which, IMO, is a point in Antoine's favor.  Let's see what Michael has to say.
msg157870 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-04-09 17:52
> Antoine: I've used the pattern you describe on a couple of occasions,
> and it routinely confuses my code reviewers.

Really? What is confusing about it?
Perhaps we should simply document it.
msg157894 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2012-04-09 20:42
So the technique I suggested is that the TestLoader checks classes for the "testbase" (or whatever we call it) *in the class dict*. So inheritance doesn't matter - a class is only excluded from test loading if it has the attribute directly.
msg157896 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2012-04-09 20:45
Here are my objections to the standard (but not widely used outside our own tests) mixin pattern for base testcases (copied and pasted from issue 14408):

Because you then have classes that inherit from object calling methods that clearly don't exist (until you subclass them *and* TestCase). It looks weird and also means the classes can't be tested in isolation.

With a class decorator the code would *look* straightforward, and the hidden attribute is just an implementation detail.

It still looks weird to see code calling methods that obviously don't exist, and with no indication *at the call site* where they come from. Making it clearer with naming would help: "TestThingMixin" or similar.

There are classes like this in the unittest test suite, and I was very confused by them initially until I found where and how they were used. It is obviously *not* a pattern that is widely known for test base classes, as we have this problem of it not being done even in the standard library tests.

In contrast I think code similar to the following would be clear and readable without knowing about multiple inheritance and the mixin trick:

    @test_base_class
    class SomeTestBase(TestCase):
        ...

Besides which, the mixin pattern won't *stop* working if we provide this extra functionality - it would just be an alternative for those (like myself) who think it impedes code readability. :-)

At this point we're off topic for the *specific issue*, and I'm fine with our own standard library tests moving to use mixins to support standard unittest invocation. I would suggest the base test cases include Mixin in their name to make it clear how they should be used.
msg157898 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-04-09 20:47
> So the technique I suggested is that the TestLoader checks classes for
> the "testbase" (or whatever we call it) *in the class dict*. So
> inheritance doesn't matter - a class is only excluded from test
> loading if it has the attribute directly.

Why not document the official recommendation in the docs?
Adding another gimmick isn't very useful. It doesn't add a
functionality. It doesn't even make it significantly easier to write
tests (unless you have more test classes than test methods). And it
means that people have to remember two idioms instead of one.
msg157910 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-04-09 21:57
Note that I did just document the mixin idiom in the Lib/test docs.  Which core developers probably don't read :)
msg158222 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2012-04-13 17:54
FWIW I use the mixin approach too and find it simple and clean.  I don’t have a problem with a method in the mixin class calling methods from TestCase.
msg158252 - (view) Author: Kristján Valur Jónsson (kristjan.jonsson) * (Python committer) Date: 2012-04-14 10:34
+1, we already have such decorators for individual test cases. Code should be obvious, particularly testing code and mixins often aren't. Magic such as identifying classes to run by their type should be over rideable. All magic should.
History
Date User Action Args
2012-04-14 10:34:01kristjan.jonssonsetnosy: + kristjan.jonsson
messages: + msg158252
2012-04-13 17:54:09eric.araujosetnosy: + eric.araujo
messages: + msg158222
2012-04-09 21:57:55r.david.murraysetmessages: + msg157910
2012-04-09 20:47:56pitrousetmessages: + msg157898
2012-04-09 20:45:54michael.foordsetmessages: + msg157896
2012-04-09 20:42:09michael.foordsetmessages: + msg157894
2012-04-09 17:52:11pitrousetmessages: + msg157870
2012-04-09 17:50:38r.david.murraysetmessages: + msg157869
2012-04-09 17:45:09stutzbachsetnosy: + stutzbach
messages: + msg157868
2012-04-09 17:24:09pitrousetnosy: + pitrou
messages: + msg157867
2012-04-09 13:10:52r.david.murraycreate