Testing Blog

How to Write 3v1L, Untestable Code

štvrtok, júla 24, 2008
Share on Twitter Share on Facebook
Google
Menovky: Misko Hevery

31 komentárov :

  1. thomas25. júla 2008 o 5:18:00 GMT-7

    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!

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  2. Mike25. júla 2008 o 6:06:00 GMT-7

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  3. Misko25. júla 2008 o 7:49:00 GMT-7

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  4. Misko25. júla 2008 o 7:51:00 GMT-7

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  5. Martin25. júla 2008 o 10:02:00 GMT-7

    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'. :)

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  6. Eric Jain25. júla 2008 o 11:32:00 GMT-7

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  7. Demian L. Neidetcher25. júla 2008 o 12:23:00 GMT-7

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

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  8. Mark Roddy25. júla 2008 o 13:35:00 GMT-7

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  9. Soon Hui26. júla 2008 o 7:26:00 GMT-7

    Writing testable code is harmful.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  10. redsolo26. júla 2008 o 14:45:00 GMT-7

    @misko

    Will the Testability explorer catch these lovely tips and tricks?

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  11. Imam Alam27. júla 2008 o 5:45:00 GMT-7

    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!

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  12. JamesDumay27. júla 2008 o 7:16:00 GMT-7

    Yeah, the sarcasm was "great".

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  13. Misko27. júla 2008 o 11:09:00 GMT-7

    @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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  14. Kristian J.29. júla 2008 o 7:42:00 GMT-7

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  15. Yuri31. júla 2008 o 16:28:00 GMT-7

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  16. Michael1. augusta 2008 o 6:47:00 GMT-7

    3v1L fails the spellchecker unit test

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  17. Steve24. augusta 2008 o 14:23:00 GMT-7

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  18. Narayan26. septembra 2008 o 3:59:00 GMT-7

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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  19. Herregud10. novembra 2008 o 6:26:00 GMT-8

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  20. Igor19. novembra 2008 o 20:22:00 GMT-8

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  21. Herregud3. marca 2009 o 6:48:00 GMT-8

    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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  22. Anonymný21. marca 2009 o 7:59:00 GMT-7

    Tento komentár bol odstránený správcom blogu.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  23. Anonymný11. mája 2009 o 1:33:00 GMT-7

    Tento komentár bol odstránený správcom blogu.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  24. Mark T. Tomczak5. novembra 2009 o 15:03:00 GMT-8

    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?

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  25. Davis5. novembra 2009 o 15:38:00 GMT-8

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  26. Matth5. novembra 2009 o 17:58:00 GMT-8

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  27. jfmiller285. novembra 2009 o 18:17:00 GMT-8

    You missed the big one: Multi-threaded code!

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  28. offline6. novembra 2009 o 1:26:00 GMT-8

    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).

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  29. Peter Hickman6. novembra 2009 o 6:02:00 GMT-8

    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

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  30. joedevon8. novembra 2009 o 6:30:00 GMT-8

    unsarcastic positive repost++

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
  31. Anonymný17. októbra 2013 o 12:32:00 GMT-7

    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.

    OdpovedaťOdstrániť
    Odpovede
      Odpovedať
Pridať komentár
Načítať viac...

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)
    • ►  okt (1)
    • ►  sep (1)
    • ►  aug (1)
    • ►  júl (1)
    • ►  máj (3)
    • ►  apr (3)
    • ►  mar (1)
    • ►  feb (1)
  • ►  2023 (14)
    • ►  dec (2)
    • ►  nov (2)
    • ►  okt (5)
    • ►  sep (3)
    • ►  aug (1)
    • ►  apr (1)
  • ►  2022 (2)
    • ►  feb (2)
  • ►  2021 (3)
    • ►  jún (1)
    • ►  apr (1)
    • ►  mar (1)
  • ►  2020 (8)
    • ►  dec (2)
    • ►  nov (1)
    • ►  okt (1)
    • ►  aug (2)
    • ►  júl (1)
    • ►  máj (1)
  • ►  2019 (4)
    • ►  dec (1)
    • ►  nov (1)
    • ►  júl (1)
    • ►  jan (1)
  • ►  2018 (7)
    • ►  nov (1)
    • ►  sep (1)
    • ►  júl (1)
    • ►  jún (2)
    • ►  máj (1)
    • ►  feb (1)
  • ►  2017 (17)
    • ►  dec (1)
    • ►  nov (1)
    • ►  okt (1)
    • ►  sep (1)
    • ►  aug (1)
    • ►  júl (2)
    • ►  jún (2)
    • ►  máj (3)
    • ►  apr (2)
    • ►  feb (1)
    • ►  jan (2)
  • ►  2016 (15)
    • ►  dec (1)
    • ►  nov (2)
    • ►  okt (1)
    • ►  sep (2)
    • ►  aug (1)
    • ►  jún (2)
    • ►  máj (3)
    • ►  apr (1)
    • ►  mar (1)
    • ►  feb (1)
  • ►  2015 (14)
    • ►  dec (1)
    • ►  nov (1)
    • ►  okt (2)
    • ►  aug (1)
    • ►  jún (1)
    • ►  máj (2)
    • ►  apr (2)
    • ►  mar (1)
    • ►  feb (1)
    • ►  jan (2)
  • ►  2014 (24)
    • ►  dec (2)
    • ►  nov (1)
    • ►  okt (2)
    • ►  sep (2)
    • ►  aug (2)
    • ►  júl (3)
    • ►  jún (3)
    • ►  máj (2)
    • ►  apr (2)
    • ►  mar (2)
    • ►  feb (1)
    • ►  jan (2)
  • ►  2013 (16)
    • ►  dec (1)
    • ►  nov (1)
    • ►  okt (1)
    • ►  aug (2)
    • ►  júl (1)
    • ►  jún (2)
    • ►  máj (2)
    • ►  apr (2)
    • ►  mar (2)
    • ►  jan (2)
  • ►  2012 (11)
    • ►  dec (1)
    • ►  nov (2)
    • ►  okt (3)
    • ►  sep (1)
    • ►  aug (4)
  • ►  2011 (39)
    • ►  nov (2)
    • ►  okt (5)
    • ►  sep (2)
    • ►  aug (4)
    • ►  júl (2)
    • ►  jún (5)
    • ►  máj (4)
    • ►  apr (3)
    • ►  mar (4)
    • ►  feb (5)
    • ►  jan (3)
  • ►  2010 (37)
    • ►  dec (3)
    • ►  nov (3)
    • ►  okt (4)
    • ►  sep (8)
    • ►  aug (3)
    • ►  júl (3)
    • ►  jún (2)
    • ►  máj (2)
    • ►  apr (3)
    • ►  mar (3)
    • ►  feb (2)
    • ►  jan (1)
  • ►  2009 (54)
    • ►  dec (3)
    • ►  nov (2)
    • ►  okt (3)
    • ►  sep (5)
    • ►  aug (4)
    • ►  júl (15)
    • ►  jún (8)
    • ►  máj (3)
    • ►  apr (2)
    • ►  feb (5)
    • ►  jan (4)
  • ▼  2008 (75)
    • ►  dec (6)
    • ►  nov (8)
    • ►  okt (9)
    • ►  sep (8)
    • ►  aug (9)
    • ▼  júl (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
    • ►  jún (6)
    • ►  máj (6)
    • ►  apr (4)
    • ►  mar (4)
    • ►  feb (4)
    • ►  jan (2)
  • ►  2007 (41)
    • ►  okt (6)
    • ►  sep (5)
    • ►  aug (3)
    • ►  júl (2)
    • ►  jún (2)
    • ►  máj (2)
    • ►  apr (7)
    • ►  mar (5)
    • ►  feb (5)
    • ►  jan (4)

Feed

  • Google
  • Privacy
  • Terms