On Mon, May 9, 2011 at 6:06 PM, Corey Richardson <kb1...@aim.com> wrote:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On 05/09/2011 07:11 PM, Kirby Urner wrote: > > It's like doctest but different in that we're not showing interactions, > > though we could be. > > I saw in #python that someone was working on making doctest even more > useful, and having some of the features of unittest (and I believe he > was working on running doctests from unittests). I don't mind doctest in > smaller quantities, and sphinx makes it look good on the user-facing side. > > When I'm teaching newcommers I used to avoid testing until the last > possible moment (even in my AP CS class we never once had to have formal > tests for our code...) to cover it, and it was scanty. Now I usually > teach mostly full TDD with the doctest module, and then show them > unittest later on. I think it makes the docstrings look ugly, but > testing is more important than aesthetics. > > my 2c, > - -- > Corey Richardson > Seems a reasonable approach. Likewise this OST curriculum sanely begins with core basics, phases in doctest, then unittest. The TDD philosophy is well demonstrated and the author (SH) walks his talk. However, I'm thinking to wedge something TDDish between doctest and unittest that's just the engaged coder testing her own module in top-level run mode (versus importing). It's one of those delegating of responsibility things that a module should have some standalone behaviors to model / demo what it brings to the table. To that end, a structure like: def _test( ): """ testing code goes here, TDD is your friend """ if __name__ == "__main__": _test( ) is considered "good to go". How does this support the "write tests first" philosophy? Well, imagine having this class: class Farm: def __init__(self, rows=8, columns=8, bg="*"): self.h = rows self.w = columns self.bg = bg # background character self.tractors = [] # like Snake or Dog stomach self.field = [list(bg*self.w) for x in range(self.h)] # model self.framenumber = 0 self.trace = [] def render(self): display="" for line in self.field: display += "".join(line)+"\n" return display # view __str__ = render def __repr__(self): return "Farm({},{}) @ {}".format(self.w, self.h, id(self)) It basically builds an M x N array of stars, and now you want to add the feature that you can peek or poke to that array using a FORTRAN-like syntax i.e. >>> myfarm = Farm(10,20) >>> myfarm(3, 5) = "@" will "plant" a "@" in row 3 column 5 of the data structure, named self.field. The coder would simply embed this expected feature in _test: def _test(): myfarm = Farm(10,20) # before picture print(myfarm) myfarm(3, 5) = "@" # after picture print(myfarm) It's clear to the coder what's expected, so there's the test. Now the goal is to add the minimum code to Farm that makes this work. Example (continued): class Farm: # << code already shown >> def __getitem__(self, key): # from arr4.py "Returns the appropriate element for a two-element subscript tuple." r, c = key return self.field[r][c] # from arr4.py def __setitem__(self, key, value): "Sets the appropriate element for a two-element subscript tuple." r, c = key self.field[r][c] = value Run the module top-level, triggering _test, and do so again and again, as contingencies and corner cases get tested. Leave a representative set of tests behind as evidence of your audit. You may write a more formal unittesting framework later, but there's no guarantee that's something to release with the module. The _test( ) function serves as an "on board payload" while the unittest framework stays behind "near the launch pad". The goal is to put the learner in the role of Quality Assurance tester, at least at first. Eat your own dog food. Keep the code to be tested and the tester code together, but that doesn't have to mean doctest. Kirby
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig