Merge lp:~mbp/bzr/fixtures into lp:bzr

Proposed by Martin Pool on 2010-05-14
Status: Merged
Merged at revision: 5317
Proposed branch: lp:~mbp/bzr/fixtures
Merge into: lp:bzr
Diff against target: 117 lines (+86/-0)
4 files modified
NEWS (+3/-0)
bzrlib/tests/__init__.py (+1/-0)
bzrlib/tests/fixtures.py (+40/-0)
bzrlib/tests/test_fixtures.py (+42/-0)
To merge this branch: bzr merge lp:~mbp/bzr/fixtures
Reviewer Review Type Date Requested Status
Robert Collins (community) 2010-05-14 Resubmit on 2010-05-23
Review via email: mp+25337@code.launchpad.net

Description of the Change

This adds the camel's nose of test fixtures as a separate comment.

The specific case I start with is generating unicode strings for use in tests.

See also http://rbtcollins.wordpress.com/2010/05/10/maintainable-pyunit-test-suites/#comment-161

To post a comment you must log in.
lp:~mbp/bzr/fixtures updated on 2010-05-14
5232. By Martin Pool on 2010-05-14

Change factories from make_ to choose_

Robert Collins (lifeless) wrote :

Firstly, setUp and tearDown are a great way to separate specification ('I want 4 branches, 3 repositories, 2 servers and a merge proposal in my test') and instantiation ('Dude, where are my branches?'). So I think that setUp/tearDown or a similar pairing are really good to have, because if we do want to be able to have reusable fixtures or declarative fixtures, we won't want to have all their overhead at test suite load time. decorators are another way to achieve that, but it ends up just being function currying, and you don't seem to be taking a decorate-and-insert approach here, either.

Secondly, AIUI you want to head towards a 'what, not how' approach - but this new fixture seems a bit unclear about which it is.

Oh, and are you aware of self.getUniqueString on TestCase? We'll probably want to migrate such things across eventually - it might be worth peeking at its implementation to see how some existing do-things-uniquely code is hanging together. In particular, and I know its trivial, the manual counting for unique numbers seems like a case where you could experiment with how you want things to compose.

All in all I think this can shape up nicely, but I'd like to see a bit more please. Marking work in progress, as after 9 days unreviewed I don't think someone else is going to pop up Right Now :)

If you'd like to land just this bit I'd be ko with that if you add setup and teardown to the contract, and a reference - base class, or standalone do-nothing - that describes the contract and how you hope people will use it.

review: Resubmit
Martin Pool (mbp) wrote :

On 24 May 2010 07:17, Robert Collins <email address hidden> wrote:
> Review: Resubmit
> Firstly, setUp and tearDown are a great way to separate specification ('I want 4 branches, 3 repositories, 2 servers and a merge proposal in my test') and instantiation ('Dude, where are my branches?'). So I think that setUp/tearDown or a similar pairing are really good to have, because if we do want to be able to have reusable fixtures or declarative fixtures, we won't want to have all their overhead at test suite load time. decorators are another way to achieve that, but it ends up just being function currying, and you don't seem to be taking a decorate-and-insert approach here, either.

Are you saying that the contract of the fixture should have a
setUp/tearDown, or that they should be constructed from the setUp of
the TestCase? If the former then I do agree, as we discussed in
person a while ago. It's useful to separate construction of the
object from its actual preparation. The rationale should be
documented though.

>
> Secondly, AIUI you want to head towards a 'what, not how' approach - but this new fixture seems a bit unclear about which it is.

Agree on both points ;-) I think I'm still trying things on.

>
> Oh, and are you aware of self.getUniqueString on TestCase? We'll probably want to migrate such things across eventually - it might be worth peeking at its implementation to see how some existing do-things-uniquely code is hanging together. In particular, and I know its trivial, the manual counting for unique numbers seems like a case where you could experiment with how you want things to compose.

No, I wasn't aware of that. Anyhow, it is an interesting case -
ideally we want something that scales from that to something very
expensive.

--
Martin <http://launchpad.net/~mbp/>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-05-14 09:02:35 +0000
3+++ NEWS 2010-05-14 15:49:24 +0000
4@@ -206,6 +206,9 @@
5 Testing
6 *******
7
8+* Add ``bzrlib.tests.fixtures`` to hold code for setting up objects
9+ to test. (Martin Pool)
10+
11 * Added ``bzrlib.tests.matchers`` as a place to put matchers, along with
12 our first in-tree matcher. See the module docstring for details.
13 (Robert Collins)
14
15=== modified file 'bzrlib/tests/__init__.py'
16--- bzrlib/tests/__init__.py 2010-05-14 08:10:35 +0000
17+++ bzrlib/tests/__init__.py 2010-05-14 15:49:24 +0000
18@@ -3700,6 +3700,7 @@
19 'bzrlib.tests.test_export',
20 'bzrlib.tests.test_extract',
21 'bzrlib.tests.test_fetch',
22+ 'bzrlib.tests.test_fixtures',
23 'bzrlib.tests.test_fifo_cache',
24 'bzrlib.tests.test_filters',
25 'bzrlib.tests.test_ftp_transport',
26
27=== added file 'bzrlib/tests/fixtures.py'
28--- bzrlib/tests/fixtures.py 1970-01-01 00:00:00 +0000
29+++ bzrlib/tests/fixtures.py 2010-05-14 15:49:24 +0000
30@@ -0,0 +1,40 @@
31+# Copyright (C) 2005-2010 Canonical Ltd
32+#
33+# This program is free software; you can redistribute it and/or modify
34+# it under the terms of the GNU General Public License as published by
35+# the Free Software Foundation; either version 2 of the License, or
36+# (at your option) any later version.
37+#
38+# This program is distributed in the hope that it will be useful,
39+# but WITHOUT ANY WARRANTY; without even the implied warranty of
40+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41+# GNU General Public License for more details.
42+#
43+# You should have received a copy of the GNU General Public License
44+# along with this program; if not, write to the Free Software
45+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
46+
47+
48+"""Fixtures that can be used within tests.
49+
50+Fixtures can be created during a test as a way to separate out creation of
51+objects to test. Fixture objects can hold some state so that different
52+objects created during a test instance can be related. Normally a fixture
53+should live only for the duration of a single test.
54+"""
55+
56+
57+class UnicodeFactory(object):
58+
59+ def __init__(self):
60+ self._counter = 0
61+
62+ def choose_string(self):
63+ """Return a new short unicode string."""
64+ self._counter += 1
65+ # use a mathematical symbol unlikely to be in 8-bit encodings
66+ return u"\N{SINE WAVE}%d" % self._counter
67+
68+ def choose_encoding(self):
69+ """Return a new Python string encoding."""
70+ return 'cp850'
71
72=== added file 'bzrlib/tests/test_fixtures.py'
73--- bzrlib/tests/test_fixtures.py 1970-01-01 00:00:00 +0000
74+++ bzrlib/tests/test_fixtures.py 2010-05-14 15:49:24 +0000
75@@ -0,0 +1,42 @@
76+# Copyright (C) 2005-2010 Canonical Ltd
77+#
78+# This program is free software; you can redistribute it and/or modify
79+# it under the terms of the GNU General Public License as published by
80+# the Free Software Foundation; either version 2 of the License, or
81+# (at your option) any later version.
82+#
83+# This program is distributed in the hope that it will be useful,
84+# but WITHOUT ANY WARRANTY; without even the implied warranty of
85+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86+# GNU General Public License for more details.
87+#
88+# You should have received a copy of the GNU General Public License
89+# along with this program; if not, write to the Free Software
90+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
91+
92+"""Tests for test fixtures"""
93+
94+import codecs
95+
96+from bzrlib import (
97+ tests,
98+ )
99+from bzrlib.tests import (
100+ fixtures,
101+ )
102+
103+
104+class TestTestFixtures(tests.TestCase):
105+
106+ def test_unicode_factory(self):
107+ unicode_factory = fixtures.UnicodeFactory()
108+ ss1 = unicode_factory.choose_short_string()
109+ self.assertIsInstance(ss1,
110+ unicode)
111+ # default version should return something that's not representable in
112+ # ascii
113+ self.assertRaises(UnicodeEncodeError,
114+ ss1.encode, 'ascii')
115+
116+ # the encoding chosen by the factory is supported by Python
117+ codecs.lookup(unicode_factory.choose_encoding())