Testing Blog

Writing Testable Code

Wednesday, August 06, 2008
Share on Twitter Share on Facebook
Google
Labels: Misko Hevery

32 comments :

  1. Jonathan PryorAugust 6, 2008 at 10:16:00 AM PDT

    I don't know how to unit-test the main method!

    Obviously you have no imagination. You test the same method the same way you test static methods: provide known input, and test that the output is what you expect given the input.

    Which is exactly the same way you'd test Math.abs() and numerous other static methods. (Which is exactly the way I test C# extension methods, e.g. http://anonsvn.mono-project.com/source/branches/rocks-playground/Tests/Mono.Rocks.Tests/IEnumerableTest.cs)

    To make this "easy", you should attempt to mandate that static methods operate on no mutable state -- following the idioms of functional programming -- or provide some mechanism to reset the global state that the method operates on to a known value.

    Remember: global state is also an input to the static method if the method uses the global state.

    You can, of course, take this to a "higher level": console input and output is also global state, so if your main method reads from or writes to the terminal, you can have a shell-based unit test which invokes your program (with some set of arguments) and compares the programs output to what was actually generated.

    This isn't difficult. Tedious, sure, but not difficult, and extremely useful to do when first starting to write unit tests for a pre-existing project (which may not have used any OO design methodology to begin with).

    Just remember the first rule of testing any unit of code (method, library, program, operating system...): check the code's output against known input and compare against known-good output. The rest are details.

    ReplyDelete
    Replies
      Reply
  2. UnknownAugust 7, 2008 at 3:05:00 AM PDT

    "[If your] class has static methods that only operate on parameters [then] you have a class which mixes concerns"

    I have a class named Importer which has a static method:
    Customer ReadCustomer(IDataRecord record)

    This method only operates on its parameter. It creates a new Customer object from the IDataRecord.

    Could you please describe how this class 'mixes concerns'? I'm not entirely sure how it is doing so.

    ReplyDelete
    Replies
      Reply
  3. John WebberAugust 7, 2008 at 5:17:00 AM PDT

    Miško, in the paragraph about static methods you refer to "seems" - do you mean "seams?" Otherwise I'm not sure what you mean...

    ReplyDelete
    Replies
      Reply
  4. Michael RogerAugust 7, 2008 at 8:23:00 AM PDT

    Sponge, I believe the point is that any pure method (that relies only on its parameters) can be separated into a pure utility class, leaving less code that depends on the class members.

    "Separation of concerns" didn't put a fine point on it, but the goal is to eliminate uneccessary dependencies, much like the Fuel/FuelTank example earlier.

    ReplyDelete
    Replies
      Reply
  5. UnknownAugust 7, 2008 at 8:32:00 AM PDT

    If you get past a number of typos and the non-working links, it looks like a hastily written, non-proofed copy.

    ReplyDelete
    Replies
      Reply
  6. Gary BruntonAugust 7, 2008 at 8:43:00 AM PDT

    Excellent article! I love seeing these types of topics from this blog.

    Keep them coming.

    ReplyDelete
    Replies
      Reply
  7. Max CantorAugust 7, 2008 at 12:14:00 PM PDT

    You wrote:

    If you see a switch statement you should think polymorphisms. If you see the same if condition repeated in many places in your class you should again think polymorphism.

    Could you perhaps give a little code snippet that exemplifies this? That is, what would a switch statement "look like" when turned into a polymorphic solution instead?

    ReplyDelete
    Replies
      Reply
  8. UnknownAugust 7, 2008 at 1:07:00 PM PDT

    Max "Could you perhaps give a little code snippet that exemplifies this?"

    Assume you have a class named "Message" with a method named "sendMessage()" that contains this fragment :

    if (this.messageType = messageTypes.Fax) {
    ...
    }

    then you should probably have a FaxMessage class that inherits from Message and overrides sendMessage().

    ReplyDelete
    Replies
      Reply
  9. Imran FanaswalaAugust 7, 2008 at 1:38:00 PM PDT

    @Max,

    Let's say you are developing a chat service that combines various chat protocols, and you want to implement logout() functionality.

    Switch version:
    http://pastebin.com/f23bf0c6e

    Polymorphic version:
    http://pastebin.com/fae7a445

    Admittedly, the above example is not the most apt but it is based of a real world refactoring I did a while ago. If you want a more typical example, try http://hanuska.blogspot.com/2006/08/swich-statement-code-smell-and.html

    Regards,
    Imran Fanaswala

    ReplyDelete
    Replies
      Reply
  10. GrobyAugust 7, 2008 at 1:45:00 PM PDT

    Hm. You have me stumped with the "ask, don't look for" advice.

    Who exactly would I be asking for the objects I need if I *don't* pass in a ServiceLocator? A global service locator instead?

    ReplyDelete
    Replies
      Reply
  11. heliosAugust 7, 2008 at 1:50:00 PM PDT

    More about polymorphism:

    maybe examples on how to use polymorphism can be found in the strategy pattern (Gamma 1994). It happens a lot of time (the most when your building some kind of tool/framework) you need to do a generic work (loading database field values into an object, by example), but this generic thing has it's specialties (converting types, converting special values, getting the value, etc). That's when you delegate that special thing (converter.getValueFromBD(...)) and use polymorphism to implement it in various ways (IntegerConverter, ClobToStringConverter, StringConverter, etc, etc, etc).

    By the way: strategy is a pattern like template-method except that it preffers composition [using a strategy] than inheritance [overriding the template method]. It illustrate the point about composition vs. inheritance.

    ReplyDelete
    Replies
      Reply
  12. heliosAugust 7, 2008 at 2:01:00 PM PDT

    groby:

    asking:

    There are two ways. None of them use a ServiceLocator.

    1) receiving what you need directly in the constructor/setter. I mean: if you need something let your client code give it to you.

    new Car(FuelTank)

    2) receiving a Provider (NOT A SERVICELOCATOR).
    It's a subttle diferrence:

    A ServiceLocator is bad because it's a general/global entry-point. It's application-aware, not component-aware. So your code becomes less independent.

    A Provider (as I propose it) is an interface defined by the very class you are writing and who implements it ONLY does that.

    example:

    new Engine(FuelProvider)

    as I cannot give fuel to the engine directly on the constructor (it's going to ask for it when it runs) I have to give it when the class wants. So that class (Engine) defines the interface FuelProvider:

    examples.car.engine.Engine
    examples.car.engine.FuelProvider

    and somebody implement it how he/she wants:

    examples.car.NormalFuelProvider implements
    examples.car.engine.FuelProvider
    {
    // uses FuelTank
    }

    NormalFuelProvider is more application-dependant that FuelProvider interface. It's fine because it's created for wiring things in an application (assume car is the application). At least, in the example is something that's made for creating a car with an Eingne and a FuelTank.

    Getting back to the ServiceLocator what I mean is you can implement a Provider that's aware of the ServiceLocator but your class Engine not.

    If you want to test it you can give an AllTheFuelYouWantProvider that do mock-like stuff so you can concentrate on the Engine. You don't have to worry about any ServiceLocator (or FuelTank), don't have to worry about application-like code, and your tests are happier.

    ReplyDelete
    Replies
      Reply
  13. ihathAugust 7, 2008 at 4:27:00 PM PDT

    interesting article

    ReplyDelete
    Replies
      Reply
  14. Max CantorAugust 8, 2008 at 12:11:00 PM PDT

    @Imran and @Michel:

    Thanks! This seems like something I've done for a while without knowing what it was called. I appreciate the explanation!

    ReplyDelete
    Replies
      Reply
  15. Dave KirbyAugust 8, 2008 at 12:23:00 PM PDT

    This is an interesting article, but the list is rather confusing. Some of the titles are things that you SHOULD do, and some are things that you should NOT do. It is only when you read the body of the list that it becomes clear (and sometimes even then it is not always obvious). I suggest prepending each list item with DO or DONT to make it clear, or rewriting them to make them consistent.

    To be specific, all of the points are things you should NOT do, except for 2, 7 and 8, which you SHOULD do.

    ReplyDelete
    Replies
      Reply
  16. UnknownAugust 26, 2008 at 4:38:00 PM PDT

    If you have a spring project and you want to test a dao - how do you do that *easily*.

    Everyone just says, "use dbunit".

    But I don't see how that makes it easy.

    ReplyDelete
    Replies
    1. AnonymousSeptember 14, 2012 at 12:04:00 AM PDT

      Build yourself a test fixture using an in-mem database, and add database initialization code to the test fixture class. Sure, it's some overhead, but if you do it right, you only do it once for all DAO tests you write in an application - and IME there are many of them.

      Delete
      Replies
        Reply
    2. AnonymousSeptember 14, 2012 at 12:27:00 AM PDT

      Organizing your code into value objects and services is highly non-OO, and was named by (IIRC) Fowler the anemic domain model. I have used it successfully in several LOB apps, but it is specifically damaging when the interactions between your domain-specific objects are rich and complex (like for example in a physical simulation of a system if interacting particles). In such cases, organizing your code into value objects and services rightout harms testability. Therefore I wouldn't include this advice in the list.

      Delete
      Replies
        Reply
    3. MisrajiDecember 28, 2012 at 8:00:00 PM PST

      @Florin:
      I do follow your argument about not organizing code into value object and service objects for simulation software.

      But my theoretical understand of OO is that an object is Procedural abstraction of Data. That is data being represented purely by its behavior.
      Service Objects perfectly fit the definition. What is being hidden, is their own state, which should be nobody's concern.

      OTH, not all data can be represented by behavior only. In such cases, having a value object makes sense.

      Thus IMHO, the advice about dividing the code into Value Objects and Service Objects still seems reasonable.

      Is my reasoning incorrect?

      Delete
      Replies
        Reply
    4. Reply
  17. Ran TavoryJune 28, 2009 at 6:23:00 AM PDT

    About Singletons, I completely agree. I posted this article on my blog: http://prettyprint.me/2009/06/24/beware-of-the-singleton/

    ReplyDelete
    Replies
      Reply
  18. Edward HuynhSeptember 2, 2009 at 11:38:00 PM PDT

    Excellent topic and content. Keep them coming

    ReplyDelete
    Replies
      Reply
  19. Geshan ManandharMarch 22, 2010 at 7:34:00 AM PDT

    If I could wrap my head around it, I"ll try :).

    ReplyDelete
    Replies
      Reply
  20. jenniferMay 14, 2010 at 5:03:00 AM PDT

    it's good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.

    ReplyDelete
    Replies
      Reply
  21. Kalle KarlbergMay 21, 2011 at 3:05:00 AM PDT

    Great article. I tried for one hour+ to make this point to a colleage y-day. I'll just send her this article.

    ReplyDelete
    Replies
      Reply
  22. MikeDecember 2, 2011 at 4:03:00 PM PST

    Good article, most points I agree with. However, there is a strong Java/C# bias in your explanations (or pure OOP bias), and it might be good to stress that fact as some points don't apply as strongly to other languages. Also, this statement made be jump out of my chair:

    "Polymorphism: at compile-time the method you are calling can not be determined"

    You need to review your basic software engineering knowledge. The definition you give pertains to "dynamic binding", not polymorphism. Polymorphism is essentially the concept of substitutability of types. In other words, being able to substitute one object-type for another and be able to reuse the same method that uses either types is the key aspect of polymorphism (i.e. the object types are polymorphic types and the functions using them are polymorphic functions). This does NOT require dynamic binding, it is only if you need to make this substitution at run-time that dynamic binding is required. Haven't you heard of something called "static polymorphism" (i.e. polymorphism that is realized at compile-time). This also exemplifies my point about the strong OOP bias in your article. I write an enormous amount of procedural code (in C++), heavily relying on static polymorphism, and thus, has a lot of "seams" making the construction of unit-tests very easy (and generally sticking to state-less functional programming is also a huge benefit in that regard). Certainly, in OOP, good use of dynamic polymorphism will make unit-testing a lot easier, but this does not mean that procedural programming (that doesn't use dynamic polymorphism) is hard to unit-test, it's just hard to do so if you suck at writing procedural code.

    So overall, I would say that point 6 should be taken out (or left with a strong caveat that this applies only to highly restrictive programming languages that don't allow you to achieve static polymorphism). Then, points 4 and 5 are the same (do you really think anyone who knows what a Singleton is doesn't know that it's forms a global state). Point 3 only applies to languages with reference-semantics with non-deterministic construction models (Java/C# and the like), in a language like C++, this point is mute (unless you are emulating Java/C# style OOP in C++, which is just a very bad style of C++). The remaining points are good IMO.

    Just my grain of salt.

    ReplyDelete
    Replies
      Reply
  23. UnknownJuly 20, 2012 at 5:25:00 AM PDT

    Do you test the code that creates the object graph? If so, how?

    ReplyDelete
    Replies
      Reply
  24. MisrajiDecember 29, 2012 at 1:42:00 PM PST

    How does one deal with dynamically created objects (say) like objects representing email?

    ReplyDelete
    Replies
      Reply
  25. UnknownAugust 21, 2013 at 7:57:00 AM PDT

    I guess "branches" would be the correct term as opposed to "seams".

    ReplyDelete
    Replies
      Reply
  26. Robert PeszekOctober 8, 2014 at 6:20:00 PM PDT

    Continuing on the OOP bias point (Mike December 2, 2011).
    FP is becoming more and more popular and OO languages allow for more and more of a FP/OOP mix.

    If you think about this list in therms of FP, all points are N/A!

    In this context, I would like to suggest a shorter list to produce a much more testable code:
    1) limit side-effects
    2) isolate side-effects

    Also, in the context of FP, I very much disagree with point 6. The term 'method' is somewhat redeeming but...
    A true FP language like Haskell will have a very 'static' feel to it. In OOP/FP hybrid if you want to code with functions instead of methods these functions will need to have static presence too. For example: if 'reduce' is a function that accept an accumulator and a list (instead of being a method owned by the list), it has to exist outside of the list object. I took the approach of using lots of static definitions when designing fpiglet (FP library for Groovy) and I believe it to be some of the most testable code I ever done within the boundaries of an OO language.

    ReplyDelete
    Replies
      Reply
  27. UnknownOctober 22, 2016 at 12:31:00 PM PDT

    RDM vs. ADM
    ----------------------------------------------------------------

    If you separate logic from data in an Object Oriented language, you actually fall back to procedural programming. (A.K.A, by Fowler, "ADM")

    Many companies do that for the sake of testing.

    However, if you still want to write real Object Oriented and benefit a rich domain model:

    1. Separate your project to modules.
    2. Each module will have a thin service layer made of stateless logic.
    3. Use "new" to instantiate business objects.
    4. Use service locator or IoC container to resolve services provided by other modules.

    ReplyDelete
    Replies
      Reply
  28. MPursleyOctober 9, 2018 at 5:19:00 PM PDT

    Thanks for the article. Awesome tips!

    While reading through it, I found some things that sound like typos or minor grammatical errors? I'll post them here, in case you have time/interest to fix them. :) I'll post them into the copy on your blog too.


    Thanks!
    Matt

    ___
    - "OK, you got rid of your new operators in you application code." ->
    "OK, you got rid of your new operators in your application code."

    - "Global state is bad from theoretical, maintainability, and understandability point of view," ->
    "Global state is bad from theoretical, maintainability, and understandability points of view,"

    - "The core of the issue is that the global instance variables have transitive property!" ->
    "The core of the issue is that the global instance variables have a transitive property!"

    - "Seams are needed so that you can isolate the unit of test." ->
    "Seams are needed so that you can isolate the unit test."

    - "If you build an application with nothing but static methods you have procedural application." ->
    "If you build an application with nothing but static methods you have a procedural application."

    - "I don't know how to test application without seams." ->
    "I don't know how to test an application without seams."

    - "How much a static method will hurt from a testing point of view depends on where it is in you application call graph." ->
    "How much a static method will hurt from a testing point of view depends on where it is in your application call graph."

    - "At run-time you can not chose a different inheritance, but you can chose a different composition, this is important for tests as we want to test thing in isolation." ->
    "At run-time you can not choose a different inheritance, but you can choose a different composition, this is important for tests as we want to test a thing in isolation."

    - "This will clutter the focus of test" ->
    "This will clutter the focus of the test"

    - "This helps testing since simpler/smaller class is easier to test." ->
    "This helps testing since a simpler/smaller class is easier to test."

    - "If summing up what the class does includes the word "and", or class would be challenging for new team members to read and quickly "get it", or class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns." ->
    "If summing up what the class does includes the word "and", or the class would be challenging for new team members to read and quickly "get it", or the class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns."

    - "These classes are hard to tests since there are multiple objects hiding inside of them and as a resulting you are testing all of the objects at once." ->
    "These classes are hard to tests since there are multiple objects hiding inside of them and as a result, you are testing all of the objects at once."
    ___

    ReplyDelete
    Replies
      Reply
  29. Google Testing BloggersOctober 31, 2018 at 7:17:00 AM PDT

    Fixed! Thanks!

    ReplyDelete
    Replies
      Reply
Add comment
Load more...

The comments you read and contribute here belong only to the person who posted them. We reserve the right to remove off-topic comments.

  

Labels


  • TotT 104
  • GTAC 61
  • James Whittaker 42
  • Misko Hevery 32
  • Code Health 31
  • Anthony Vallone 27
  • Patrick Copeland 23
  • Jobs 18
  • Andrew Trenk 13
  • C++ 11
  • Patrik Höglund 8
  • JavaScript 7
  • Allen Hutchison 6
  • George Pirocanac 6
  • Zhanyong Wan 6
  • Harry Robinson 5
  • Java 5
  • Julian Harty 5
  • Adam Bender 4
  • Alberto Savoia 4
  • Ben Yu 4
  • Erik Kuefler 4
  • Philip Zembrod 4
  • Shyam Seshadri 4
  • Chrome 3
  • Dillon Bly 3
  • John Thomas 3
  • Lesley Katzen 3
  • Marc Kaplan 3
  • Markus Clermont 3
  • Max Kanat-Alexander 3
  • Sonal Shah 3
  • APIs 2
  • Abhishek Arya 2
  • Alan Myrvold 2
  • Alek Icev 2
  • Android 2
  • April Fools 2
  • Chaitali Narla 2
  • Chris Lewis 2
  • Chrome OS 2
  • Diego Salas 2
  • Dori Reuveni 2
  • Jason Arbon 2
  • Jochen Wuttke 2
  • Kostya Serebryany 2
  • Marc Eaddy 2
  • Marko Ivanković 2
  • Mobile 2
  • Oliver Chang 2
  • Simon Stewart 2
  • Stefan Kennedy 2
  • Test Flakiness 2
  • Titus Winters 2
  • Tony Voellm 2
  • WebRTC 2
  • Yiming Sun 2
  • Yvette Nameth 2
  • Zuri Kemp 2
  • Aaron Jacobs 1
  • Adam Porter 1
  • Adam Raider 1
  • Adel Saoud 1
  • Alan Faulkner 1
  • Alex Eagle 1
  • Amy Fu 1
  • Anantha Keesara 1
  • Antoine Picard 1
  • App Engine 1
  • Ari Shamash 1
  • Arif Sukoco 1
  • Benjamin Pick 1
  • Bob Nystrom 1
  • Bruce Leban 1
  • Carlos Arguelles 1
  • Carlos Israel Ortiz García 1
  • Cathal Weakliam 1
  • Christopher Semturs 1
  • Clay Murphy 1
  • Dagang Wei 1
  • Dan Maksimovich 1
  • Dan Shi 1
  • Dan Willemsen 1
  • Dave Chen 1
  • Dave Gladfelter 1
  • David Bendory 1
  • David Mandelberg 1
  • Derek Snyder 1
  • Diego Cavalcanti 1
  • Dmitry Vyukov 1
  • Eduardo Bravo Ortiz 1
  • Ekaterina Kamenskaya 1
  • Elliott Karpilovsky 1
  • Elliotte Rusty Harold 1
  • Espresso 1
  • Felipe Sodré 1
  • Francois Aube 1
  • Gene Volovich 1
  • Google+ 1
  • Goran Petrovic 1
  • Goranka Bjedov 1
  • Hank Duan 1
  • Havard Rast Blok 1
  • Hongfei Ding 1
  • Jason Elbaum 1
  • Jason Huggins 1
  • Jay Han 1
  • Jeff Hoy 1
  • Jeff Listfield 1
  • Jessica Tomechak 1
  • Jim Reardon 1
  • Joe Allan Muharsky 1
  • Joel Hynoski 1
  • John Micco 1
  • John Penix 1
  • Jonathan Rockway 1
  • Jonathan Velasquez 1
  • Josh Armour 1
  • Julie Ralph 1
  • Kai Kent 1
  • Kanu Tewary 1
  • Karin Lundberg 1
  • Kaue Silveira 1
  • Kevin Bourrillion 1
  • Kevin Graney 1
  • Kirkland 1
  • Kurt Alfred Kluever 1
  • Manjusha Parvathaneni 1
  • Marek Kiszkis 1
  • Marius Latinis 1
  • Mark Ivey 1
  • Mark Manley 1
  • Mark Striebeck 1
  • Matt Lowrie 1
  • Meredith Whittaker 1
  • Michael Bachman 1
  • Michael Klepikov 1
  • Mike Aizatsky 1
  • Mike Wacker 1
  • Mona El Mahdy 1
  • Noel Yap 1
  • Palak Bansal 1
  • Patricia Legaspi 1
  • Per Jacobsson 1
  • Peter Arrenbrecht 1
  • Peter Spragins 1
  • Phil Norman 1
  • Phil Rollet 1
  • Pooja Gupta 1
  • Project Showcase 1
  • Radoslav Vasilev 1
  • Rajat Dewan 1
  • Rajat Jain 1
  • Rich Martin 1
  • Richard Bustamante 1
  • Roshan Sembacuttiaratchy 1
  • Ruslan Khamitov 1
  • Sam Lee 1
  • Sean Jordan 1
  • Sebastian Dörner 1
  • Sharon Zhou 1
  • Shiva Garg 1
  • Siddartha Janga 1
  • Simran Basi 1
  • Stan Chan 1
  • Stephen Ng 1
  • Tejas Shah 1
  • Test Analytics 1
  • Test Engineer 1
  • Tim Lyakhovetskiy 1
  • Tom O'Neill 1
  • Vojta Jína 1
  • automation 1
  • dead code 1
  • iOS 1
  • mutation testing 1


Archive


  • ►  2025 (1)
    • ►  Jan (1)
  • ►  2024 (13)
    • ►  Dec (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (1)
    • ►  May (3)
    • ►  Apr (3)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2023 (14)
    • ►  Dec (2)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (3)
    • ►  Aug (1)
    • ►  Apr (1)
  • ►  2022 (2)
    • ►  Feb (2)
  • ►  2021 (3)
    • ►  Jun (1)
    • ►  Apr (1)
    • ►  Mar (1)
  • ►  2020 (8)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  May (1)
  • ►  2019 (4)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Jul (1)
    • ►  Jan (1)
  • ►  2018 (7)
    • ►  Nov (1)
    • ►  Sep (1)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (1)
    • ►  Feb (1)
  • ►  2017 (17)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (2)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2016 (15)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (1)
    • ►  Sep (2)
    • ►  Aug (1)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (1)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2015 (14)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Aug (1)
    • ►  Jun (1)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (1)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2014 (24)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Sep (2)
    • ►  Aug (2)
    • ►  Jul (3)
    • ►  Jun (3)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2013 (16)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Jan (2)
  • ►  2012 (11)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (1)
    • ►  Aug (4)
  • ►  2011 (39)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (2)
    • ►  Aug (4)
    • ►  Jul (2)
    • ►  Jun (5)
    • ►  May (4)
    • ►  Apr (3)
    • ►  Mar (4)
    • ►  Feb (5)
    • ►  Jan (3)
  • ►  2010 (37)
    • ►  Dec (3)
    • ►  Nov (3)
    • ►  Oct (4)
    • ►  Sep (8)
    • ►  Aug (3)
    • ►  Jul (3)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (3)
    • ►  Mar (3)
    • ►  Feb (2)
    • ►  Jan (1)
  • ►  2009 (54)
    • ►  Dec (3)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (5)
    • ►  Aug (4)
    • ►  Jul (15)
    • ►  Jun (8)
    • ►  May (3)
    • ►  Apr (2)
    • ►  Feb (5)
    • ►  Jan (4)
  • ▼  2008 (75)
    • ►  Dec (6)
    • ►  Nov (8)
    • ►  Oct (9)
    • ►  Sep (8)
    • ▼  Aug (9)
      • Taming the Beast (a.k.a. how to test AJAX applicat...
      • Root Cause of Singletons
      • TotT: Sleeping != Synchronization
      • Where Have All the Singletons Gone?
      • Singletons are Pathological Liars
      • TotT: 100 and counting
      • TotT: A Matter of Black and White
      • Writing Testable Code
      • GTAC Attendance Application deadline Aug15
    • ►  Jul (9)
    • ►  Jun (6)
    • ►  May (6)
    • ►  Apr (4)
    • ►  Mar (4)
    • ►  Feb (4)
    • ►  Jan (2)
  • ►  2007 (41)
    • ►  Oct (6)
    • ►  Sep (5)
    • ►  Aug (3)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (7)
    • ►  Mar (5)
    • ►  Feb (5)
    • ►  Jan (4)

Feed

  • Google
  • Privacy
  • Terms