-3

I've been trying to learn TDD in Python for a number of months after hearing many programmers, who are much more talented and skilled than I am, extolling the virtues of it. I definitely see the benefit in tests, which I don't argue at all. What I'm having a tough time with is the basic workflow of TDD (as I understand it):

  1. Think of the next bit of code you need to write.
  2. For that bit of code, write a test that fails what that bit of code is supposed to achieve.
  3. Run the program you're testing, asserting that it fails where expected.
  4. Write the bit of code that you think will make the test in 3 succeed, and repeat until it does.
  5. Repeat!

The biggest reason I'm having a tough time getting into this flow is the amount of time it takes up. The way I interpret it, for each line of code that may have taken me 30 seconds to write individually takes at least a minute. Consider the following example:

import requests
r = requests.get('http://stackoverflow.com/')
print(r.status_code)
>>> 200

Not a useful block of code certainly, but it completes a task and checks the status of the completion. I wrote that in about 30 seconds in my 'non-TDD' way. The equivalent written in TDD-style would require at least twice as long, because of switching between scripts, writing the test that fails, asserting that the test indeed does fail, then writing the use of the get method, etc. etc.

Then, the second problem I have is this: what use is the test? If I assert that the status_code is 200, haven't I really just been testing the logic that's written in the requests module? What do I learn from tests that I absolutely know are going to fail, or absolutely know are going to succeed based on the logical conditions I'm testing within?

One possible problem my thought process has is that I simply haven't learned enough TDD - i.e., maybe it's painful at the beginning to get you in the habit of judiciously writing tests, but eventually it becomes second nature. Even if that is the case though, seamlessly writing a test still takes time, and that amount of time grows as your application grows in complexity.

I'm quite sure that I must be wrong about all of this, as I've read so many people who are "at" the level I want to achieve some day saying such good things about TDD. So, where is my thinking going wrong?!

n1c9
  • 2,662
  • 3
  • 32
  • 52
  • It's a lot easier to write your tests before or even during the time you write the code. If you don't, the likelyhood of getting 100% coverage after you move on to the next piece diminish significantly. That, or you break something far away when writing new code and the old code doesn't yet have tests, you may not even realize you've created a bug... and yes, in the beginning, it does seem to be a pain. – stevieb Jan 13 '17 at 18:13
  • As far as your example test, you wouldn't re-test the module, you'd want to test the return for your specific case, so that if you don't get `200`, you can take action (such as skipping other tests that require an internet connection for instance). – stevieb Jan 13 '17 at 18:15
  • If you're writing a module, you *have* to write code to see if it does what you want, so why not take the extra cycles and turn it into a proper unit test? – stevieb Jan 13 '17 at 18:16
  • I think it depends on your business requirements and beliefs about the likely future of your project. If your goal is to deliver an MVP, or something akin to a prototype that has a high risk of short-term failure (from a business perspective) then strict TDD is likely not going to be a smart approach. On the other hand, TDD is quite helpful for mature projects / projects you know will be around for a long time and where the cost of introducing a bug is high. – David Simic Jan 13 '17 at 18:33
  • @stevieb What if you're just writing a script, not a module? Is TDD supposed to be used more with modules than standalone scripts? – n1c9 Jan 13 '17 at 18:49
  • 1
    The idea is that you don't necessarily "learn" from tests, but write them for future use, when you make changes in your code or use new parameter values. Then you just run your old tests to make sure no errors are introduced. – postoronnim Jan 13 '17 at 19:00

1 Answers1

1

Writing the test is more like a way to think about the requirements and how to achieve those things. To my point of view, maybe you need to use some TDD frameworks. I think one of the reasons why you feel difficult doing TDD is Python did not have significant TDD frameworks (Although people are saying: Life is short so I use Python). If you use Ruby and Rspec, you will find TDD is not that tough.

By using some frameworks, you can easily design your test logics and for many of the steps you write today, you can simply reuse them in your future test case.

Hope this can help you:

Is there a python equivalent for RSpec to do TDD?

Also, if you wanna explore more into the TDD world, you can try with BDD. I would recommend you to use Python Behave if you are interested in playing with BDD.

http://pythonhosted.org/behave/

Quick example, say you wanna test the requests library

You can write your test cases like

When I try to request "https://stackoverflow.com/"
Then I could get response code is "200"

And in BDD you can define your steps like

@when('I try to request "{my_url}"')
def step_impl(context, my_url):
    context.last_result = requests.get(my_url)

@then('I could get response code is "{code}"')
def step_impl(context, code):
    context.last_result.status_code.should.be.eq(code)

Once you hit here, you can simply use your steps tomorrow as

When I try to request "fake_url"
Then I could get response code is "404"

When I try to request "url_needs_autho"
Then I could get response code is "401"

You can now test whatever behavior of your library or function. Life is short so I use Python

Community
  • 1
  • 1
Chong
  • 335
  • 2
  • 9