Mid-Michigan CFUG MXUnit Presentation Roundup

Tuesday, January 13, 2009

Thanks! To all who attended, thanks for spending so much time with me. And thanks to Rick and Nick for setting it all up. Here's some follow-up: Remember my onMissingMethod / UserBean problem? Turns out, the reason the test was failing was that I needed to call user.setid(id=5), not user.setid(5). Umm...... that ain't cool. So I wrote some notes into bean.cfc and userbean.cfc for refactoring. Give those refactorings a shot! Follow-up, or, What to do next
  1. Go download MXUnit
  2. If you're using Eclipse, install the Eclipse plugin
  3. Somewhere in your codebase, create a directory named "tests" (or whatever)
  4. Pick a fairly easy existing component that you've already written. Let's say it's named "Bob". Now, go to your tests directory and create a new file called "BobTest.cfc".
  5. Inside that file, add a cfcomponent tag and have it extend mxunit.framework.TestCase
  6. Then, pick a function in Bob to run. Maybe it's "init". Think to yourself, "What's one thing this function should do?" Then, back in your test, write a new test function, something like ....
  7. Run the test to confirm everything's "hooked up" correctly. This test should pass.
  8. Now, try to write a simple test for Bob.init() by creating an instance of Bob and invoking its init() function. Write an assertion or two on the result of that call to init().
Congrats! You've now written your first test. Then.... Next time you add a function to a component, write a test for it first. Think to yourself, "What should this function do?" If it does more than one thing (like maybe "init" returns self but also adds arguments to the variables scope), then write two functions, one for each "behavior". And then use those functions to run the function-under-test in your component, and write assertions that prove the behavior is as expected. Adopt the habit of writing tests for the expected behavior of your components. Practice As practice, Here's where we left off with the initial tests on the Feed processing in the ColdFusionBloggers code. Download it, and try the following: Open the components/querysim_instructions.txt and do what it says Open the components/creating a directory test runner.txt and do what it says. Open components/UserRefactored.cfc and UserRefactoredTest.cfc and read my comments. Give the TODOs a shot if you're feeling frisky. Or, at the very least, *think* about how you might approach it... use it as a thought experiment try refactoring the feed-processing file (scheduled/processes.cfm) into the Processor.cfc to make it easier to test. Work iteratively... a little bit of improvement at a time. ProcessTest.cfc is already stubbed for you. Then, post your results back here, or send them to the MXUnit Google Group and we can talk about it there. Stick with it, and good luck! You have a lot of people out here willing to help. When things get tough to test Bill and I presented at MAX 08 on some solid strategies for when the going gets tough with testing. Definitely check out the download and the Recording of the presentation, which is now on adobe TV. Links are in here.


billy said...

> I needed to call user.setid(id=5), not user.setid(5).

I'm really glad you mentioned this, because I ran into this same issue on another project. This behavior has got me a bit confused ... did you find any resource explaining why this is? Or what's your take on it?


Marc Esher said...

in this specific case, the problem is in the implementation of onMissingMethod inside of bean.cfc. As practice, I've set up a function to test to ensure that bean.setid(5) works... it's up to folks to download the zip file and refactor the onMissingMethod to get that call to work. it's entirely doable, quite simply even.

so i don't think this is a coldfusion onMissingMethod problem. this is a specific implementation problem

Mike said...

I always thought that was caused by not supplying a value to all of your arguments in the same order they are listed in your method. Throw in an optional argument and your hosed if you don't include the names.

Is there more to it that that?

billy said...

dang ... I'm going to have to think this morning ...

Marc Esher said...

@mike: nope, that's it. the thing is, in this specific case, the problem is in an onMissingMethod function that's attempting to do dynamic getters/setters. the nice thing about this is that a setter will only take a single argument. so it's easy to implement onMissingMethod to just not care about named args.

So here's a case where you can get around a lame problem in onMissingMethod b/c the implementation is attempting to do a very simple/specific thing.

for more complicated onMissingMethod implementations, I'm not sure it'd be so easily dealt with.