While writing a simple utility API used to modify Excel documents I ran into an annoying situation. My end-to-end integration test was loading a test file, making a modification, verifying that the file was changed, and reversing the modification. This worked great except that each time I ran the tests (all the time), the file’s timestamp would be changed. This meant that every time I wanted to commit back to SVN, the file showed up as modified.
After noticing that this simple test file had a few dozen commits associated with it without any real change in values … I needed to find a better solution to setting-up and tearing-down my test data.
Enter File.createTempFile(). While surfing the always helpful Java Almanac I found a nice little tip to on how to create a temporary file in the system’s default temp directory. According to the javadoc, the method will create a new empty file in the sytem’s default temp directory with a given prefix and file extension. After the chosen prefix, the utility will generate a new random code. This combined with File.deleteOnExit() allowed me to have my tests execute against a new file each time that is automatically cleaned up when the JVM closes which saves my commit logs.
It might not be perfect as a long term solution, but for now, it perfectly solved my problem.
I have been forcing myself to use TestNG lately because its what my current client uses and to try something new. Overall I have been happy with it, but I don’t think I will be switching from JUnit any time soon on projects where I have a choice. Yes, TestNG has several features which JUnit doesn’t, but JUnit 4 made up a lot of ground from when TestNG was first released in response to the shortcomings of JUnit 3. Plus, a lot of the features I just don’t think I would use very often.
One feature that did make a lot of sense to me was the idea of test groups. Basically, the @Test annotation allows you to specify any number of strings as group names that the given test will belong to. Then, when you want to execute a test suite, you can specify which groups are included or excluded from your suite. Sounds simple enough and would allow you to divide up your test executions if you wanted to. So I gave it a shot.
I wrote up a new test, gave it a label of “integration” (distinguishing it from my normal unit tests) and tried to run it. ERRRR. NullPointerException. After several minutes verifying I had things setup correctly I realized the problem was that my @BeforeSuite and @BeforeMethod methods were not being called. But the the test was working a minute ago …. a quick check of the docs revealed that all of the @BeforeXXX and @AfterXXX methods ALSO can have a groups setting. Meaning that when I told TestNG to run just the tests with a group of “integration” I was really telling it to only execute methods with that group.
This wasn’t the behavior I was expecting, but at least I understood what was going on after I read the docs. If I added the group to my support methods, everything would be fine. Only one problem. The @BeforeXXX and @AfterXXX methods in question are in a base class and shouldn’t need to know about any groups a test class wants to use.
Enter the alwaysRun annotation property. According to the TestNG docs:
For before methods (beforeSuite, beforeTest, beforeTestClass and beforeTestMethod, but not beforeGroups): If set to true, this configuration method will be run regardless of what groups it belongs to.
For after methods (afterSuite, afterClass, …): If set to true, this configuration method will be run even if one or more methods invoked previously failed or was skipped.
By adding this to the base class, the correct methods are run each time. I am not 100% sure this won’t have other side effects that I haven’t found yet, but as it stands, it allows me to use groups in my tests AND use the base class to setup and teardown some of our common objects. Its not a perfect solution, but it works.
I wanted to catalog my currently available programmable processing power, eventually satisfying the questions that Norvig Wants to Know:
- IBM Thinkpad T42 outfitted with Fedora 10, 2GB of RAM, 1.7GHz Pentium M processor, ??? GB Hard drive. This is my main machine. My workhorse. I’m terrible about backing it up, even though I’ve gone to the trouble to craft the right rsync command and have plenty of external drives with lots of space on them laying around. What’s worse is that every new release of Fedora entices me to do a hasty backup of my home directory and upgrade. Its like I’m asking for it.
- Dell tower that I bought off Saint Louis University’s Law School IT dept for $75, shitty processor (P2, maybe) and small HD (couple hundred MB), almost no memory to speak of. Its currently running Arch Linux, because the Haskell guys have such good things to say about the distro. I’m excited about the fact that the base distro is light (no heavy desktop environment or system services to speak of) so anywhere it goes from here will be the result of my efforts. That’s an opinion I probably didn’t hold a year ago — not being savvy enough to make all of those decisions — but its becoming increasingly important to me with every piece of software I uninstall from my Fedora box.
- Also available to me as storage, are two Maxtor external USB hard drives. 300 and 200GB in size.
- I own a TI-83+ calculator, none of that silver bullshit, its got the Zilog-80 processor (?? MHz) and 160Kb of flash memory (I think).
- I own a HP-15C in perfect working condition. Something like 96-something words (read: bytes) of memory, and an even slower processor, but its a cool tool to hack on beause unlike any other platform I’ve worked on, you are always conscious of the fact that processing speed and memory are precious, exhaustable resources.
- Old Original Xbox, has a CPU, a GPU some amount of memory and a hard drive. Its basically an off-the-shelf computer. There are some security measures to get around, though.
- I own a PSP with a cracked screen, rendering it — unlike my fully functional Xbox 360 — sacrificable to the gods of hackery.
- A spare Linksys B router that I don’t use.
If my comfortable world ended tomorrow and I had to build autonomous, roving robots to stride the city and wreak devastation upon plagues of the undead, I guess I could probably sacrifice the following to serve as those robot’s brain:
- A network-critical Linksys G router, which isn’t as readily hackable as, say, the WRTL versions.
- Xbox 360 with an attached 20GB hard drive.
Today I was having some trouble coming up with a Selenium XPath locator for a deeply nested selector with a dynamically generated ID. To make matters worse, there were no “near by” logical elements that this element was tied to that had an easy locator. The only clear thing I had was the label for the option I wanted to select. Not wanting to leave the test w/ an extremely brittle, not to mention long and unreadable, xpath locator … I remembered that I had solved this problem before.
Several times now I have wanted to use an XPath expression to find an element by its child element. Queue XPath axes.
Since I have forgotten the syntax and usage of axes several time nows, here I post the solution for posterities sake. If anyone has a better solution to this issue, please let me know … but this seemed to work well enough.
XPath axes allow you to specify a “location step” from a[ny] specified element. What does this mean? We can select elements based on there location relative to another, and NOT just contained within it. They are specified by an “axis specifier” followed by :: and an element selector. Example:
In order to select a SELECT element by one of its OPTIONs:
//OPTION[text() = 'Choice Text']/parent::SELECT
This XPath selects the SELECT element which is the parent of any OPTION elements containing the text node with a value of ‘Choice Text’. While not as simple as a locator directly to the desired element based on its ID, this expression is composed only of elements we actually care about with regard to the test (the option we want and the selector its in) and is more readable than a 50+ character expression going back to the root element and containing numerous indexes.
XPath axes can select a number of things including an elements children, ancestors, siblings (preceding and following), etc.
Also, at least in XPather, an expression that would otherwise return the same element more than once through an axis, only returns the unique list of elements (e.g. //div/ancestor::* will return the root element only once and not once per DIV found)
As I slowly attempt to teach myself Haskell and the basics of functional programming, I will try and post some of my thoughts and confusions as they come. If anyone sees me doing something wrong, please speak up. My ego is not tied to the code I post so much as the fact that someone read it and took the time to respond.
As I was reading chapter 3 of Real World Haskell yesterday, I got myself all turned around. And, like any good man driving a car, I refused to ask for directions and kept driving around until things started to look familiar again.
The task at hand was to write a function which would convert the List data type the authors defined earlier in the chapter to a native array.
data List a = Cons a (List a)
fromList (x:xs) = Cons x (fromList xs)
fromList  = Nil
The authors also gave an example of a function which would convert arrays to Lists. My job was to create the reverse. My first attempt is below:
fromList2 List a b = a : (fromList2 b)
fromList2 Nil = 
This had some potential, but doesn’t compile complaining about a lack of a data constructor ‘List‘. My confusion was around the difference between the type constructor and the value constructor. List is the type constructor for the List type. Cons is the value constructor for an object who type happens to be a List type. Coming from a Java/C# background, when I first read about pattern matching, I immediately assumed it was matching against the type of objects. Well, that’s true and false. In Java the type and value of something are two different things. In Haskell, they are linked and can not change. Therefore, when writing a pattern matching function, we need to look at the value of the parameter (ie the value constructor and values) and NOT the “type”. I should have realized this when I wrote the second line. Nil is not the same kind of construct as List, which should have set of a red flag for me.
To make things even more confusing, when I wrote the above code to try and test my new function, I head already read the author’s comments about how since type constructors and value constructors are really two different things and can never be used where the other was intended, they are normally named the same (Cons was used for readability). Normally, and how I typed it out at first without realizing it, it would be written with both constructors named the same – List.
The other confusing thing for me was the difference between type variables and “normal” variables. When defining the new abstract type List, ‘a‘ represents a type variable, or a place holder for the type of the actually object passed in. Since nothing within the definition of a List needs to know the type of the parameter, we can get away with it being unknown until creation time. When defining a function, the variable no longer represents the objects type, but the object itself. Haskell is strongly and statically typed, but doesn’t require you to specificy exactly what type a variable is. It inferes it from how you use it.
Thus, the correct anser is:
fromList2 (Cons x xs) = x : (fromList2 xs)
fromList2 Nil = 
Trying to work with the type constructors, value constructors, type variables, etc all at once was a bit much. The way I really figured this out was to build up to it with another example. Here is the code I wrote which taught me what I was doing wrong above. Maybe it will help someone else someday.
myListOrgChart = Cons "ben" (Cons "boss" (Cons "ceo" Nil))
listOrgChart = fromList2 myListOrgChart
data Person = Employee Int String Person
| Consultant String
name (Employee _ name _) = name
name (Consultant name) = name
managerName (Employee _ _ manager) = name manager
managerName (Consultant name) = name
orgChart (Employee _ name manager) = name : orgChart manager
orgChart (Consultant name) = name : name : 
orgChart NoOne = 
ceo = Employee 1 "ceo" NoOne
boss = Employee 2 "boss" ceo
ben = Employee 3 "ben" boss
joe = Consultant "joe"
benOrgChart = orgChart ben
4th ever Lambda Lounge meeting happened last night, and even though I had to leave early, there was plenty going on to like so I wanted to spill some of my impressions quickly this morning. This meeting gets cooler and cooler every month. Appistry provides beer (as in free) and pizza (I had a slice with Doritos, jalapenos and pepperoni, changed my view of things) and next month the Lounge covers Factor and the long-awaited Parrot VM. The month after that will behold a language shootout, all topics upholding the upward trend. (thanks for the correction, Alex!)
Ken Sipe opened the night with an introduction to F#. Ken mentioned that this was his first LL, but he’s obviously done the presenting thing before. His talk was a smooth sweep of the F# language. A couple of things he said rang particularly true:
- F# is going to be big. As far as functional programming goes, most languages have power, but very few have the deep reach to actually touch developers at their desks. F# has tooling, Microsoft support and upcoming first class inclusion into the .NET platform.
Say what you want about Microsoft, but the C# language has continually impressed with a flexibility and forward progression that Java doesn’t feel like its generating anymore. With F# on the horizon and Mono making it possible to work with .NET in Linux, a lot of functional programmers may be looking Redmond’s way in the very near future.
- F# reduces noise on the signal that syntax descended from C tends to introduce.
Ken had a couple of great slides that illustrated that if nothing else, functional programming allows the programmer to express ideas with little structure, braces, etc. surrounding them. F# source is a compressed package of the data you are working on, the operations you are performing and little else. On this point, the Ruby community’s sense of aesthetics — that something functional should be short and expressive — has made all programmers look at their production code and increased all of our appetites for terseness. Until now, our languages have been making our fingers do work, and as far as IDEs and autocomplete have come, F# really brings programmers down closer to the ideas they are expressing.
- F#’s discriminated unions and pattern matching are killer.
These complementary features allow for a style of programming that is expressive and beautiful and instantly readable. Discriminated unions make disparate data simple to break down into component parts and associate with an overarching type. Pattern matching allows a function to introspect as deep into a type as it wants, as well as pick and choose cases to implement functionality with. Long branching if chains and switch statements have no reason for existence in F#. Ken’s exact quote was “we need this”.
- Michael Easter’s talk was ‘Monads are Burritos’.
It was lighthearted and exploratory. For those who know monads, Michael talked about the Maybe monad. For those of you who don’t, he stressed that monads aren’t something that you can impart knowledge of on someone else by force of will, but that everyone has to struggle with and learn for themselves. For his part on our journey, though, Easter brought props! He used a coozie, a water bottle, a two-foot length of cardboard tube, and maybe there was more, I don’t know, I had to leave after his first example of making a beverage by adding water, hops and malt. :)
Michael’s code was in Haskell and it made an excellent companion to Ken’s F# introduction as both languages share a common heritage and similar syntax. Until this is our jobs and we hate looking at Haskell or F# as much as we hate looking at Java, this is all strange and weird and promising and Easter captured that in his words, slides and examples. A lot of people asked a lot of questions at the end of Ken’s talk. I imagine the situation was similar after Michael’s. The functional space is huge, F# is only a tiny part. Monads are only a tiny part. This is certainly early-adopter territory. As many questions asked about F# were observations on various other aspects of functional programming people had encountered. This is the current spirit of the Lambda Lounge. Almost like a bunch of spies reporting back to each other on super top-secret new weapons. Until all of this is clear, the Lounge is a great place to trade intel.
While putting together my answers for all of the computing power currently available to me, I came across something interesting. My primary computer is a Thinkpad T42 running Fedora 10. It has an Intel Pentium M, and according to the ‘About This Computer’ dialog, its clocked at 1.7GHz.
Imagine my surprise when I ran
cat /proc/cpuinfo and found this:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 13
model name : Intel(R) Pentium(R) M processor 1.70GHz
stepping : 6
cpu MHz : 600.000
cache size : 2048 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr mce cx8 mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm pbe up bts est tm2
bogomips : 1196.11
clflush size : 64
600MHz!!?? Turns out my CPU, like most Intel CPUs have frequency scaling to cut down on power consumption and heat production when you don’t need all the raw horsepower. I must have caught my processor sleeping. The
cpuspeed daemon will help you scale your CPUs frequency as it is needed. Something to think about when you’re wondering if everything is running just a tad bit slower than you think it should.
Peter Norvig, the Director of Research at Google and all-around AI guru, has an article floating around on the interwebs which you may have heard of: Teach Yourself Programming in Ten Years. As near as I can tell, I’m in year 6 of 10 and intensely interested in knowing how I rank among my peers. Norvig asks a handful of questions that a programmer should know about the hardware he’s working on. As I am also mildly interested in world-domination, I’d add that each of these should be answered for every programmable processor currently available to you, I’m just trying to get a tally on the current and future hardware costs something like world-domination is going to incur.
- How long does it take for your processor to execute an instruction?
- How long does it take for your processor to fetch a word from memory with a:
- cache hit
- cache miss
- How long does it take to read consecutive words from your hard disk?
- How long does it take to seek a new location on your hard disk?
I think that a inventory of currently available programmable platforms and the answers to these questions for each should be a good baseline for discussing how to write kick-ass programs that run as fast they possibly can.
Last week I had a quick and dirty discussion w/ some coworkers about Selenium, common problems they have had using it, and features they would want in a framework build on top of Selenium and/or in support of it.
Having used Selenium for user acceptance testing and regression testing for a couple projects now, it was interesting to see how many of the people in the room had had the same issues and that most of them are as of the last time I checked, still issues. I am in no way trying to imply that the developers maintaining Selenium IDE/RC/Grid are not working hard (I noticed numerous issue fixes or niceties the last few times I pulled it down), just that there seem to be some issues that are keeping it from being a whole lot easier to use.
For posterities sake, and upon request of a couple of the attendees, I present my notes on what was discussed a couple of my own thoughts. Some are more true of user acceptance testing of web-apps in general than Selenium specifically, but still important. Its interesting how the issues/features brought up seem to fit into a few broad categories.
Technical Issues w/ Selenium
- Popups and multiple window are hard to manage and keep straight.
- Web-apps that rely heavily on DHTML and visual changes w/o a page load are hard to test b/c the only difference between a valid page and an invalid one might be the application of a specific css style (which the designers could change later w/o breaking the page)
- Some test constructs behave differently in different browsers
- Other technical issues: SSL certificates, downloading of files, proxy chaining (I have struggled with solving this for some time now. I just can’t get Se to either keep my proxy settings or use the -DproxyHost setting I provide)
Test Maintenance / Execution / Management
- How do we abstract out the Selenium environment (browser, test server, etc) from the tests while keeping test execution for the build as well as the developer simple and fast?
- How do we keep the time to execute individual tests down? What happens when the test suite takes FOREVER to run?
Best Practices (Testing/Selenium/Agile)
- How do we keep the logical idea of an element on the page seperate from the specific locators we need to tell Selenium how to find it?
- How do we make sure there are IDs or something similar on all important elements so that we don’t have locators which are 50+ character XPath expressions?
- How do we incorporate test data setup/teardown into our tests when using the IDE to generate and/or when they are written by “non developers”?
Testing Writing / Debugging
- Framework Feature Request – easy utility to spit out all of the IDs on the page. (Firebug and XPather in FF are lifesavers here)
- Complicated AJAX creates some real problems when it comes to making sure you have waited until after the logical operation has completed and knowing what has changed.
- We need to provide better error messages and/or write tests which are smaller and more readable so that the time between a test failing and understanding why it failed is minimal.
- XPath can be confusing. Period.
- DSLs and syntactic sugar over the top of Selenium make it sweeter but can become another whole language a team must learn in order to use the tool.
This could have been a comment on the previous post, but I figured my first response should be in post form.
My responses to Nate’s 5 questions:
1. Right now I am trying to fix up a few last things on my goofy Book Worm cheating application – booklouse – to finish version 1.0. I have a ton more ideas for it and still want to sit down with it and see how high I can go … but for right now I want to finish up the core functionality and move on to some other stuff for a while. Also, I have several additions/ideas for Selenium RC and/or Grid which I would love to sit down and code through. I think they could solve some real problems I have had writing and running tests.
2. I too am currently learning Haskell, but am not nearly as far along as you are. My goal for next week is to work through a few more chapters in the Real World Haskell book and try my hand at a few small programs. Along with Haskell I will be playing around with integrating Selenium tests written in TestNG into a Maven based project built and run via Continuum. I have some experience with all of those things, but never all at the same time. Should be interesting.
3. When not at my computer, I am usually spending my time with my wife watching tv, enjoying a nice dinner out or letter her beat me at board game. ;-) I am also trying to break into hard mode in Rock Band 2 still along with trying to get back into shape. Oh, and working on my house. My list of small and large projects grows exponentially faster than I have time to do them. Ahh, the joys of home ownership.
4. Ever since my undergraduate research days in college and a course I took in Genetic Algorithms / Evolutionary Computation I have yearned to do a larger project where my software learned to do things. My most obvious outlet to date for this is my mediocre attempts are writing software to play games for me better than I can play them myself. I also have interest in working with image processing, data mashups, and automation.
5. Hopefully a handful of smaller posts relaying my thoughts on Haskell and any progress/problems I come across as I try to integrate the above technologies into something usable for my client.