Probably it will be difficult for those who have not read Kent Beck’s TDD, but I think many have read it, so I ask for help. I have been fighting for 2 days, I lost it. At the end of Part 2, this is how the architecture turned out:

class TestCase: def __init__(self, name): self.name = name def setUp(self): self.result = TestResult() def run(self, result): result.testStarted() self.setUp() try: method = getattr(self, self.name) method() except: result.testFailed() self.tearDown() def tearDown(self): pass class WasRun(TestCase): def __init__(self, name): TestCase.__init__(self, name) def testMethod(self): self.wasRun=1 self.log = self.log+"testMethod " def setUp(self): self.wasRun = None self.log = "setUp " def tearDown(self): self.log = self.log + "tearDown " def testBrokenMethod(self): raise Exception class TestResult: def __init__(self): self.runCount = 0 self.errorCount = 0 def testStarted(self): self.runCount = self.runCount + 1 def testFailed(self): self.errorCount = self.errorCount + 1 def summary(self): return "%d run, %d failed" % (self.runCount, self.errorCount) class TestSuite: def __init__(self): self.tests = [] def add(self, test): self.tests.append(test) def run(self, result): for test in self.tests: test.run(result) class TestCaseTest(TestCase): def testTemplateMethod(self): test = WasRun("testMethod") test.run(self.result) assert("setUp testMethod tearDown " == test.log) def testResult(self): test = WasRun("testMethod") result = test.run(self.result) assert("1 run, 0 failed" == self.result.summary()) def testFailedResult(self): test = WasRun("testBrokenMethod") result = test.run(self.result) assert("1 run, 1 failed" == self.result.summary()) def testFailedResultFormatting(self): result = TestResult() result.testStarted() result.testFailed() assert("1 run, 1 failed" == self.result.summary()) def testSuite(self): suite = TestSuite() suite.add(WasRun("testMethod")) suite.add(WasRun("testBrokenMethod")) result = TestResult() suite.run(self.result) assert("2 run, 1 failed" == self.result.summary()) 

Next, we create a test suite, like this:

 suite = TestSuite() result = TestResult() suite.add(TestCaseTest("testTemplateMethod")) suite.add(TestCaseTest("testResult")) suite.add(TestCaseTest("testFailedResult")) suite.add(TestCaseTest("testFailedResultFormatting")) suite.add(TestCaseTest("testSuite")) result = TestResult() suite.run(result) print result.summary() 

And further Kent Beck writes "Create TestSuite object automatically based on TestCase"

I do not quite understand what this means, please tell me. I understand: instead of the 10 lines I quoted in the second listing, the test should be run in one:

 TestCaseTest().run() 

And after this line all test methods that exist in the test class should be executed. To do this, we need a constructor with no parameters and no run() method. But we already have a constructor and a run() method with parameters, that is, an overload is needed, but there is no overload in Python. So you need to create versions of these methods with default parameters. At least the right idea?

  • It seems you have a typo in the TestCaseTest class in the testSuite(self) method, the string suite = testSuite() should be suite = TestSuite() - Pavel Karateev
  • @PavelKarateev, thanks, corrected - Alexander Elizarov
  • @ AleksandrElizarov Please clarify your goal. It is not clear what you want to achieve? It is possible to learn how to write tests to your combat code and want to simplify the launch of tests. Or maybe write your test framework? Or something else? - sys_dev
  • Another point, the first line result = TestResult() is essentially superfluous, you re-create the result 5 lines below without using it before. - Pavel Karateev

2 answers 2

Original quote from the book:

There is a substantial duplication here, which was given a test class.

Yes, under here are just the lines suite.add(...) . Agree - with pens each method to add is not the most successful idea, maybe there are 100 of them. It means that I would like to implement a functional that will TestSuite from TestCaseTest methods itself, without our participation.

This can be implemented in various ways, I think the simplest:

  1. Use dir() to get the TestCaseTest methods and filter those that start with test*
  2. Create TestSuite
  3. Cycle through the list of methods from point 1 and add them to TestSuite using suite.add(TestCaseTest("имя_метода"))
  4. Now run suite.run(result) on the assembled TestSuite

You can clothe this logic, for example, in a separate class TestLoader. Here on github, a friend solved this problem: https://github.com/lenin/TDDbyExample/blob/7275d259132b44a5f24b116b4f61e47e421d7d35/PyTesting/tests.py and https://github.com/lenin/TDDbyExClean.jp; py was pretty neat in my opinion.

PS: Interesting book, thanks for the tip;)

    If your goal is to simplify running the tests, then in this case my recommendation is to put the package: pip install nose and use the start command: nosetests -v .

    • No, my goal is to write this test launch myself - Alexander Elizarov