I've begun to use TDD. As mentioned in an earlier question the biggest difficulty is handling interface changes. How do you reduce the impact on your test cases as requirements change?
“Test-driven development” refers to a style of programming in which three activities are tightly interwoven: coding, testing (in the form of writing unit tests) and design (in the form of refactoring).
What is Test Driven Development (TDD)? In layman's terms, Test Driven Development (TDD) is a software development practice that focuses on creating unit test cases before developing the actual code. It is an iterative approach that combines programming, the creation of unit tests, and refactoring.
Changing an interface requires updating code that uses that interface. Test code isn't any different from non-test code in this respect. It's unavoidable that tests for that interface will need to change.
Often when an interface changes you find that "too many" tests break, i.e. tests for largely unrelated functionality turn out to depend on that interface. That can be a sign that your tests are overly broad and need refactoring. There are many possible ways this can happen, but here's an example that hopefully shows the general idea as well as a particular case.
For instance if the way to construct an Account object has changed, and this requires updating all or most of your tests for your Order class, something is wrong. Most of your Order unit tests probably don't care about how an account is made, so refactor tests like this:
def test_add_item_to_order(self):
acct = Account('Joe', 'Bloggs')
shipping_addr = Address('123 Elm St', 'etc' 'etc')
order = Order(acct, shipping_addr)
item = OrderItem('Purple Widget')
order.addItem(item)
self.assertEquals([item], order.items)
to this:
def make_order(self):
acct = Account('Joe', 'Bloggs')
shipping_addr = Address('123 Elm St', 'etc' 'etc')
return Order(acct, shipping_addr)
def make_order_item(self):
return OrderItem('Purple Widget')
def test_add_item_to_order(self):
order = self.make_order()
item = self.make_order_item()
order.addItem(item)
self.assertEquals([item], order.items)
This particular pattern is a Creation Method.
An advantage here is that your test methods for Order are insulated from how Accounts and Addresses are created; if those interfaces change you only have one place to change, rather than every single test that happens to use Accounts and Addresses.
In short: tests are code too, and like all code, sometimes they need refactoring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With