Testing Blog

How to Write 3v1L, Untestable Code

Thursday, July 24, 2008
Share on Twitter Share on Facebook
Google
Labels: Misko Hevery

31 comments :

  1. thomasJuly 25, 2008 at 5:18:00 AM PDT

    Be Defensive - They're out to Get Your Code!
    I thought that writing defensive code was a good thing. I understand that
    this can be bad for testing, but can you specify a bit more when it's good do go defensive and when not.

    Otherwise I agree on most things, good post!

    ReplyDelete
    Replies
      Reply
  2. MikeJuly 25, 2008 at 6:06:00 AM PDT

    While the content of this post was excellent, the disingenuous, sarcastic, say-the-opposite-of-what-I-mean style of it was a complete turn-off.

    I hope you consider re-posting this information in a positive, "what-to-do" style, so that people don't have to parse through all of your negations just to get some good tips.

    ReplyDelete
    Replies
      Reply
  3. MiskoJuly 25, 2008 at 7:49:00 AM PDT

    Defensive programong is usefull if you don't trust third parties. I.e. Public APIs. but for internal APIs (APIs for your own consumption defensive programong should be replaced with good test coverage. I.e.it works not because I am defensive but because it is well tested.

    ReplyDelete
    Replies
      Reply
  4. MiskoJuly 25, 2008 at 7:51:00 AM PDT

    Yes, we will repost this list as a "Top 10 things to do to make your code testable with detailed explsanations"

    ReplyDelete
    Replies
      Reply
  5. MartinJuly 25, 2008 at 10:02:00 AM PDT

    I feel like a crappy developer when I read this. There's a lot of bad things in my software such as overuse of singletons, overuse of utility classes, interfaces are rarely used, *manager-classes and so on. I could probably say "check" next to every one of these items.

    On the other hand, almost everything (everything except for the user interface) is automatically tested after every new build and has been since I started to write the software 5 years ago. I add new test cases for every code I write and whenever someone reports a bug I add a automated test case for that as well before I fix it. I find it extremely easy to add new automated test cases.

    So my conclusion is that you can code which is easily testable even if you follow these principles. If your software has other things, such as good APIs and other kinds of open interfaces, it may not be 'untestable'. :)

    ReplyDelete
    Replies
      Reply
  6. Eric JainJuly 25, 2008 at 11:32:00 AM PDT

    I'd add to this list of how to make your code untestable: Don't bother to ever read the Google Testing Blog :-)

    ReplyDelete
    Replies
      Reply
  7. Demian L. NeidetcherJuly 25, 2008 at 12:23:00 PM PDT

    I like the sarcasm, it's similar to the must-read 'How to Write Unmaintainable Code':

    http://mindprod.com/jgloss/unmain.html

    ReplyDelete
    Replies
      Reply
  8. Mark RoddyJuly 25, 2008 at 1:35:00 PM PDT

    Great post. It reminded me of the 'How to get bad database performance' videos:
    http://tkyte.blogspot.com/2008/02/word-pathetic-never-sounded-so-good.html

    Though I do have the same doubts as Thomas on being defensive. I see that it makes testing more difficult, but that doesn't mean it's without merit. The benefits of the 'Crash Early' principle are laid out pretty well in the book 'The Pragmatic Programmer'. Though this is can be a fault if taken to an extreme (like anything else).

    I am also curious what you would define as a 'public api'. I'd say that any function that can be called by say 'Dave in the nyc office' should be considered public as you can't guarantee that Dave won't accidentally pass in some value that is out of range or his level of test coverage. Maybe Dave's team isn't that big on testing themselves.

    ReplyDelete
    Replies
      Reply
  9. Soon HuiJuly 26, 2008 at 7:26:00 AM PDT

    Writing testable code is harmful.

    ReplyDelete
    Replies
      Reply
  10. redsoloJuly 26, 2008 at 2:45:00 PM PDT

    @misko

    Will the Testability explorer catch these lovely tips and tricks?

    ReplyDelete
    Replies
      Reply
  11. Imam AlamJuly 27, 2008 at 5:45:00 AM PDT

    I was reading through the list and was going like... uh huh... uh huh... yes this is precisely why we need more referential transparent programming (purely functional programming if you prefer). if any functional programmer is reading this, feel free to use this entry as an advertisement!

    ReplyDelete
    Replies
      Reply
  12. JamesDumayJuly 27, 2008 at 7:16:00 AM PDT

    Yeah, the sarcasm was "great".

    ReplyDelete
    Replies
      Reply
  13. MiskoJuly 27, 2008 at 11:09:00 AM PDT

    @redsolo

    Testability Explorer is designed to catch many of these. I always have ideas on how to extend it to catch a lot more of these, but can't seem to find time.

    At its core the TestabilityExplorer computes the smallest number of conditionals that a given method must execute from a test. (i.e. these conditionals can not be mocked out in any way) The higher the number the less testable to code.

    Many of the 3v1L things listed here make it so that a method has very few if any places for seems therefore the number of un-mockable conditionals will be very high.

    ReplyDelete
    Replies
      Reply
  14. Kristian J.July 29, 2008 at 7:42:00 AM PDT

    "Code smell? No way - code perfume!"
    Awesome! That one made me laugh. Tre bien.
    -Kristian

    ReplyDelete
    Replies
      Reply
  15. YuriJuly 31, 2008 at 4:28:00 PM PDT

    Hmm, does it mean that google engineers don’t write their own unittests?...

    ReplyDelete
    Replies
      Reply
  16. MichaelAugust 1, 2008 at 6:47:00 AM PDT

    3v1L fails the spellchecker unit test

    ReplyDelete
    Replies
      Reply
  17. SteveAugust 24, 2008 at 2:23:00 PM PDT

    On the whole great advice.

    small beefs:

    "Favor polymorphism over conditionals" - good advice if you never think through the OO alternatives. I've seen (and have at times myself written) a lot of code that bends over backwards to avoid the odd if-else or small switch in the name of "OO". Sometimes the if-else is just clearer and more honest.

    "Create Managers and Controllers" - Good basic advice that can be taken too far. There are some places - "controllers" are great examples - that are a lot more like transaction scripts - a small number of lines of arbitrary statements - and just don't make sense to cover over with more abstraction - even a Command is often a waste of time. Gotta dispatch somewhere, just make it as clear as possible, whatever that means to your team.

    Many of these are good ideas whether you're writing tests or not. The last real entrenched "best practice" still out there (even in more agile environments) that TDD'ers have to contend with is defensive coding. I wish the Pragmatic Programmers would come out and disown (in a post-come-to-Jesus/TDD kind of way) that advice - it's the only fault in that book.

    ReplyDelete
    Replies
      Reply
  18. NarayanSeptember 26, 2008 at 3:59:00 AM PDT

    Indeed this is a good article, lot can be learnt from this. Thanks

    ReplyDelete
    Replies
      Reply
  19. HerregudNovember 10, 2008 at 6:26:00 AM PST

    Many of the things mentioned here such as static methods, final classes and making your own dependencies etc can actually be unit tested in Java. It’s just that the most common mock frameworks fail to do so. We have developed an open source framework to deal with many of these issues called PowerMock that is just an extension to EasyMock. What’s important to understand is that good design and testable design is not always the same thing.

    If you're interested please have a look at http://www.powermock.org.

    ReplyDelete
    Replies
      Reply
  20. IgorNovember 19, 2008 at 8:22:00 PM PST

    Johan,

    I understand the motivation behind PowerMock. but I wonder what coding habits the library promotes ?
    I work with the code deodorized with more than half of the 3v1L goodies and I happy original devs don't know PowerMock. I would neither understand their tests nor to have a chance to change the code when writing tests.

    ReplyDelete
    Replies
      Reply
  21. HerregudMarch 3, 2009 at 6:48:00 AM PST

    Igor,

    Sorry for the very late response, I just didn't realize that someone had replied here.

    We don't promote the use of static methods or anything of that kind. What we mean is that there's a distinction between good design and testable code. It should be up to you as a developer to choose the design, not the technical limitation of a mocking framework.

    I agree that putting PowerMock in the hands of novice programmers can do more harm than good in many cases. But I've experienced time and again that there are definitely use cases where PowerMock or similar frameworks really can help out. Especially if you're interacting with third-party frameworks or standard API's.

    But you should be careful when using PowerMock if you're used to having a mock-framework guide you towards better design, there's no doubt about that.

    /Johan

    ReplyDelete
    Replies
      Reply
  22. AnonymousMarch 21, 2009 at 7:59:00 AM PDT

    This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
      Reply
  23. AnonymousMay 11, 2009 at 1:33:00 AM PDT

    This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
      Reply
  24. Mark T. TomczakNovember 5, 2009 at 3:03:00 PM PST

    This article has been extremely helpful to me. I've been having a hard time wrapping my brain around unit testing and test-driven design; I think I see now that what I consider to be good practices are bad practices from a testing standpoint. Fascinating!

    One issue in particular that surprises me is the notion that it's bad to do "new" inside of an object's implementation. I write a lot of C++ code; I don't actually call new, but I certainly embed instances of other classes in a class I'm writing and then construct those instances. I do this because code re-use is good. Passing in objects that are used by the internal implementation of an object feels like exposing the implementation of the class in a bad way. Not to mention the fact that if you need to later change the class's implementation, you'll have to change the constructor and all the code calling that constructor in all places in the code...

    Perhaps I under-use factory functions?

    ReplyDelete
    Replies
      Reply
  25. DavisNovember 5, 2009 at 3:38:00 PM PST

    I want to throw $.02 in support of what Igor is saying. I also agree with much of the points made in this post, but I will concede that after learning how to effectively apply a framework like EasyMock, many of these issues go away, b/c the code is testable using the framework. This isn't to promote crap code, but some of the things you end up doing in your design "just to make the code testable" can go away with a proper mock framework. EasyMock is *not* hard to learn, either, by the way.

    ReplyDelete
    Replies
      Reply
  26. MatthNovember 5, 2009 at 5:58:00 PM PST

    A lot of this is specific to Java.

    For example, "avoid concrete classes use interfaces everywhere". In dynamic languages one doesn't need to play such games to mock things.

    Same goes for static methods - much easier to mock in a dynamic language. Although the OO design arguments against them may still hold.

    ReplyDelete
    Replies
      Reply
  27. jfmiller28November 5, 2009 at 6:17:00 PM PST

    You missed the big one: Multi-threaded code!

    ReplyDelete
    Replies
      Reply
  28. offlineNovember 6, 2009 at 1:26:00 AM PST

    Overall a very good article on how to write difficult to test code.

    However, I disagree with some of your assertions

    Make Your Own Dependencies
    At some point (at least in Java) you're going to have to call new in a method. This is often less of a dependency and more of a fact of life, not everything is caller specifable.

    Be Defensive - They're out to Get Your Code!

    Well, they are aren't they? Asserting that things that should definitely not be null are in fact, not null is a very good idea. If the tester is passing in a parameter as null that should not be, what are they testing for?

    It's a rock and a hard place here, either you check (and the tester complains that they can't pass in null), or you don't (and the tester complains about an NPE or other bad behavior).

    ReplyDelete
    Replies
      Reply
  29. Peter HickmanNovember 6, 2009 at 6:02:00 AM PST

    Guess you don't do a great deal of Perl at Google then or you would have had this.

    1) Loads of classes with 'beige' methods such as 'run', 'process' and 'execute'

    2) Write code like this...

    #!/usr/bin/env perl

    use URI;
    use Number::Fraction;

    sub beige {
    my ($x, $y, $z) = @_;
    $x->new($y)->$z();
    }

    print beige('URI', 'http://www.google.com', 'scheme');
    print beige('Number::Fraction', '1/2', 'to_num');

    Mwahaha

    ReplyDelete
    Replies
      Reply
  30. joedevonNovember 8, 2009 at 6:30:00 AM PST

    unsarcastic positive repost++

    ReplyDelete
    Replies
      Reply
  31. AnonymousOctober 17, 2013 at 12:32:00 PM PDT

    I'm surprised private isn't mentioned here. Before everyone starts forming a lynch mob, I am NOT trying to say that private should not be used! But from a pure testability perspective, private creates some challenges:

    1. It can be difficult to observe the effects of running a piece of code.
    2. It can be difficult to run a piece of code that you wish to test.

    In C++, you can use friend to get around these issues, but that's generally looked down upon.

    Another technique that I see people use to get around these issues is to add methods and comment them as "for test only". Like friend, this makes me feel dirty.

    You could argue that these problems result from poor design. While I'd probably agree with you, that does not help if I have some existing code that I want to test. To fix that problem, I'd have to go back in time, and tell the original author to do it differently. That's just not possible. What I need is a way to make incremental changes to that code to make it more testable.

    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)
    • ▼  Jul (9)
      • Circular Dependency in constructors and Dependency...
      • TotT: Testing Against Interfaces
      • How to Write 3v1L, Untestable Code
      • Breaking the Law of Demeter is Like Looking for a ...
      • YUI and GWT... How do you test?
      • Call for Attendance: GTAC 2008
      • How to Think About the "new" Operator with Respect...
      • TotT: EXPECT vs. ASSERT
      • Announcing: New Google C++ Testing Framework
    • ►  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