Friday, January 13, 2012

Specs2 Mockito - Invoke Injected Callback

Mockito and Specs2 work great together and make testing my code a lot of fun. I ran into a problem yesterday in which I needed to get access to a callback function that was passed into an object that I was mocking. For some concreteness, I was mocking a zookeeper client and needed to invoke the callback function I passed to "zookeeper.watchNode(path, callbackFunction)".

Up until this point, I've only needed to verify arguments from my test. I haven't needed to actually do something with the argument itself. My original approach was to use a custom matcher to capture the parameter using function matchers. But that involved a var and was rather messy.

It turns out there is a MUCH better way to do this. Called "argument capture." In my case, my code looked like this:

      // The signature of the zookeeper watch function
      val listener = capture[(Option[Array[Byte]]) => Unit]

      // create system under test, which will call watchNode internally
      new SUT(zkMock)

      // Use the arg capturers to capture the params SUT passed in
      there was one(zkMock).watchNode(path, listener)

      // Now, call the callback method
      listener.value(Some("some updated value from zookeeper"))

      SUT.someValue must_== "some updated value"

Thursday, January 12, 2012

Specs2: IndexOutOfBoundsException: 30

I was consistently seeing a java.lang.IndexOutOfBoundsException: 30 exception today while working on some code. I had written a spec with a single use case, which was marked as pending because I couldn't test my trait until I flushed out another piece of code upon which it depended.

I'd seen the error in the past, but couldn't remember how (of it) it went away. Since I was working on a pretty much skeleton spec, I figured now would be a good time to get to the bottom of it.

Well, it was pretty simple! In connecting my use case text description to the actual test, I was using a "^" instead of an "!", which also explains the other oddity I was seeing (that I had thought related to pending tests) "No source file found at src/test/scala/...", since the "^" was expecting a String as the result of my test method being run, not a Specs result. Go DSLs!

def is =
"My trait should" ^
"do what I want" ^ SpecsStub().assert() // WRONG, ^ should be !

case class SpecsStub() {
  def assert() = {
    pending
  }
}

Friday, December 2, 2011

Does File Exist in PHP Include Path?


We built a wrapper script around PHPUnit that loads and configures our application for testing so that test authors need not pepper their test files with redundant lines like "require_once dirname(...) . '/setup/file/included/in/all/tests.php'". This in itself is actually pretty cool, but that's fodder for another post =) The wrapper is a big time saver, but it comes at the price of a little consumption of internal PHPUnit implementation, most importantly how it starts itself up.

The start up invocation changed between 3.5 and 3.6 and one of those changes involved how PHPUnit autoloads classes. This introduced a problem because we needed to be able to support both versions of PHPUnit while the upgrade was underway. Fortunately it turned out that a determining factor between 3.5 and 3.6 was the presence of the "Autoload.php" file in the root of the PHPUnit extension module. Unfortunately, it turned out to be nontrivial to check for the existence of the file using the standard file_exists() method. The problem is that file_exists() doesn't check PHP's include path for relative file paths (unlike the logic of require_once()).

After a little research, we were able to solve the issue by a little bit of fun with file_get_contents, which takes an additional parameter to let it know that you'd like to check the include path for the presence of the file. Additionally, in the interest of performance, it lets you load only the first byte of the file, rather the entire thing.

// Support for newer version of PHPUnit during rollout to all VMs                                                                                         
// This will load the first byte of the file from the include path                                                                                         
// ...if it exists                                                                                                                                        
if (@file_get_contents('PHPUnit/Autoload.php', true, null, 0, 1))                                                                                          
{                                                                                                                                                          
    // File exists, we're on 3.6...
    require 'PHPUnit/Autoload.php';                                                                                                                        
    // ... other stuff
} 
else
{
    // Do stuff for 3.5
}

Check out the docs on file_get_contents for a description of the params.

Thursday, November 17, 2011

Notes From Implementing Lean Software Development - From Concept to Cash

I read the Poppendieck's book on implementing lean software development almost a year ago and I continue to go back to it for advice and insight. I finally brought myself to put together a brief summary on the first half of the book and decided to share it with my blog readers. One of the great things about the book is the set of industry examples they provide to exemplify to the points that they are making. This is especially useful to me, since I often have no debating ammunition aside from my personal beliefs. To make it easy to look up those examples, I'm including the page numbers along with the ideas below.


The book can be purchased from Amazon



  • pg 24 Early specification does NOT reduce waste, it encourages it
  • pg 28 "Do It Right the First Time"
    • This means TEST first to keep bugs OUT. It does NOT mean think of all possible future needs of the feature.
  • pg 32 Forecast predictions, not fact. Avoid "analysis paralysis."
    • Build processes that allow quick feedback and responses, rather than building for an uncertain feature
  • pg 33 "Plans are useless, but planning is indispensable" - Eisenhower
  • pg 34 Achieving high value, low stress feature delivery is impossible WITHOUT superb quality (in the form of tests)
  • pg 38 Sub-optimizing is BAD
    • E.g. Optimizing the writing of ONLY the feature code, but NOT the test code
    • --result--> More complex code, higher potential for introducing new bugs, longer to write new code
    • E.g. Optimizing ONLY your part of the process. The overall process still drags along and you get frustrated.
    • --solution--> Team ownership!
  • pg 74 7 Wastes
    • Relearning by failing to engage current knowledge
    • --solution?--> Information needs to be accessible. People should not be siloed and should talk often.
  • pg 101 Increase estimation reliability by decreasing variability (i.e. estimate and commit to smaller projects)
  • pg 105 FASTER delivery --> Reduce the number of things in WIP (queue theory)
  • pg 124 Exec thinking is so ingrained that Lean concepts are invisible
  • pg 126 Group is NOT a team until everyone is COMMITTED
    • E.g. Sports - track versus rowing
  • pg 150 Story by Rally does a great job highlighting the DRAWBACKS of Technical DEBT incurred by NOT slowing down to address untested code
  • pg 151 You must *commit* to action items coming out of Retrospectives
    • Nothing is accomplished if you only discuss problems.
  • pg 153 More important than processes is LEARNING (understanding), SHARING, and SOLVING PROBLEMS
    • Experience over documentation. 
    • Refined documentation far outweighs garrulous documentation

Sunday, November 13, 2011

HTML5 Drag and Drop - Chrome Not Working?

The W3C standard defines seven event types for drag and drop, http://dev.w3.org/html5/spec/dnd.html#dndevents.  Pretty cool to have so many options, but the nieve reader may be surprised to learn how they work together. Specifically, for people binding to the "drop" event.

The default behavior of the dragover event is described as such, "Reset the current drag operation to 'none'". So what does this mean for developers binding to the drop event? It means, that unless you prevent the default behavior of dragover, your drop event will not fire. This is not a fun one to learn on your own.

Friday, November 11, 2011

Could not evaluate: Could not retrieve information from source(s)

Oops! I was evaluating a template, NOT a file.

file {
    "/destination/file/path":
          source => template("path/to/template");
}

The key is that "source" should be "content"!


file {
    "/destination/file/path":
          content => template("path/to/template");
}

So, what was happening behind the scenes is that puppet was trying to source the literal value of the evaluated template file. Could be useful?

Thursday, November 10, 2011

Reading /etc/rc.status

What Cool Bash Stuff Did I Learn?
  • What does RC Stand For? ==> Resource Control
  • How do I tell vim my file type is Bash? 
    • I can set the following anywhere in the file,
      • # vim: set filetype=sh
      • # vim: syntax=sh
  • How can I make my if()s look prettier? ==> Use {}
    [ -e $pathToFile ] || {
       echo >&2 "File $file does not exit"
       exit 1
    }
    
  • How do I prompt a command to ask me for input?
    • ==> cat file-to-prepend - file-to-append > output-file