Testing Blog

How to Think About the "new" Operator with Respect to Unit Testing

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

17 comments :

  1. TeoJuly 10, 2008 at 11:06:00 PM PDT

    Wow great tip; i have to learn about unit testing for my summer practice and this is an excellent starting point!

    ReplyDelete
    Replies
      Reply
  2. akuhnJuly 11, 2008 at 2:27:00 AM PDT

    Great post! We also worked with dependency injection to achieve better decomposition of tests. While you suggest to change the application, we took the approach of changing the testing framework. We separate unit under test construction from the test logic! But I think both approaches can work together very nice. Let me give an example:

    @Test
    public Kitchen testKitchen() {
    ... create some kitchen and test it...
    return kitchen;
    }

    @Test
    @Depends("testKitchen")
    public House testHouse(Kitchen kitchen) {
    ... use the kitchen to create a house and test it...
    return house;
    }

    We extended JUnit with explicit depedencies (@Depends) and use return values and parameters to inject the result of one test into the next test. If a prerequisite fails, all dependees are skipped.

    We call our approach "Example Driven", because (other than eg mocks) our objects are actually real example instances of the unit under test. And each test method is an example of how to use it.

    More see JExample

    cheers,
    AA

    ReplyDelete
    Replies
      Reply
  3. Michael FoordJuly 11, 2008 at 4:53:00 AM PDT

    Ah, but you just don't have this problem with Python. Dynamic languages (in general) are *so* much easier to test.

    "In this updated version of House it is not possible to instantiate House without the Kitchen."

    In Python this statement is simply not true.

    You patch the name 'Kitchen' at the module level, and house will use the patched Kitchen rather than the original.

    ReplyDelete
    Replies
      Reply
  4. Josh PetersJuly 11, 2008 at 6:51:00 AM PDT

    @fuzzyman: Javascript too supports gorilla (nee guerilla) patching.

    IMHO Dependency Injection sets my code up for better design as I am freed to use interfaces more throughout my code.

    I prefer dependency injection to gorilla patching as I'm freed to declare behavior inside the testing class (where I want it) instead of creating a bogus unit that mocks something else.

    ReplyDelete
    Replies
      Reply
  5. Michael FoordJuly 11, 2008 at 6:58:00 AM PDT

    @Josh

    We (Resolver Systems) use a combination of both - although we probably do a bit too much mocking in unit tests.

    I often find that dependency injection just adds *another* layer that also needs to be tested though.

    ReplyDelete
    Replies
      Reply
  6. Josh PetersJuly 11, 2008 at 8:38:00 AM PDT

    @fuzzyman

    Yeah, I'm pretty familiar with mocking too much (both in the context of testing and regular life) ;)

    I'm a Java guy so I'm using Spring for all of my injection needs (which is pretty well tested).

    Layers are great so long as they add flexibility and don't get in your way.

    ReplyDelete
    Replies
      Reply
  7. Shyam SeshadriJuly 11, 2008 at 8:52:00 PM PDT

    This should become the holy grail for testing. +42 for dependency injection.

    ReplyDelete
    Replies
      Reply
  8. Pai RicoJuly 12, 2008 at 12:22:00 AM PDT

    Languages with powerful meta programming -often dynamic languages but not necessarily- surely ease the pain but some caution is needed:

    http://fragmental.tw/2008/01/08/please-do-not-break-into/


    --

    About Depency Injection, it is not about "asking for your dependencies instead of creating them". That's is the Registry pattern:

    http://martinfowler.com/eaaCatalog/registry.html

    Dependency Injection *is about having all dependencies automagically fulfilled by something* -often a container.

    cheers

    ReplyDelete
    Replies
      Reply
  9. Shyam SeshadriJuly 12, 2008 at 9:32:00 AM PDT

    I disagree, what you are suggesting that "ask for what you need" is not DI but rather Registry doesn't seem right. The registry patten seems to be basically a global object which allows you to retrieve what you want. DI is the concept of an object saying I need all these dependencies to work correctly, and whoever creates the object provides them.

    The registry pattern is a global object where you put in whatever you might ever need, and then look them up. THe total antithesis to DI, because it not only makes everything stored in some static context, it also makes life miserable for testing because to test, you then have to setup the registry with your mock instead of the original and let it get it. Nastiness....

    ReplyDelete
    Replies
      Reply
  10. Pai RicoJuly 12, 2008 at 8:15:00 PM PDT

    Hi,

    The Registry object doesn't have to be one global object, actually you could have different registries for different dependencies. You also don't need a static context. I think you may be thinking implementations like JNDI, that are not good at all, but these are problems with the implementation and not the pattern. A problem in the Registry pattern is that someone will have to instantiate the Registry and add dependencies to it.

    Anyway, yes, the Registry is the antithesis of Dependency Injection and that's what I've tried to explain in my last comment.

    When you say that an object asks for its dependencies you imply that it asks *something* for those. In Dependency injection you won't ask anyone, you just declare your dependencies to whoever is interested in those (via constructor signature or metadata) and assume that those will be fulfilled when you need them.

    If you ask something you will have to ask what has your dependencies. The role of Registry is exactly to hold dependencies so clients can ask or them.

    So, my conclusion is that if you ask for your dependencies you are often using Registry (as you have to ask somebody). If you declare your dependencies and assume they'll be there when you need you use Dependency Injection.

    cheers

    ReplyDelete
    Replies
      Reply
  11. Shyam SeshadriJuly 12, 2008 at 9:59:00 PM PDT

    ah I see what you are getting at. Well, with the ask approach, I believe what he basically means is that the constructor just says that I need this, and it is up to who ever is using that class to provide it. You can go one step higher and plug in a framework which provides all of these, or you might have to, in your main class, construct the object graph creating all the base and calling these constructors which ask for these things.

    So in that way, it moves away from a registry pattern. True you can use a registry pattern to satisfy this as well, but it allows you to inject mocks and ignore objects which you don't care about.

    Of course, you could just use Guice or Spring which allows easy dependency injection and managing dependencies which create your object graph, and why wouldn't you ? It makes life so much easier :D

    ReplyDelete
    Replies
      Reply
  12. Pai RicoJuly 12, 2008 at 11:26:00 PM PDT

    Hm.. I don't know, I think our problem -or my disagreement- is in the semantic of "ask". I don't have any problems with the examples presented here, they *do* represent Dependency Injection for me.

    The only point I disagree in this article is this sentence:

    "Asking for your dependencies instead of constructing them withing the application logic is called 'Dependency Injection' and is nothing new in the unit-testing world.".

    As I said DI (and the example provided in this post) is not about asking anything, it is about declaring your dependencies.

    The House featured in this text won't ask for a Kitchen, it just declares that it needs one. Asking for a kitchen would be something like:


    class House {

    private final Kitchen kitchen;

    public House(Kitchen kitchen) {

    this.kitchen = somethingThatHasKitchens.getKitchen();

    }
    //...
    }

    And that's not what happens. With or without a proper framework like guice or Spring or Pico the House in the example just declares what it needs, it won't ask for a dependency or create their own objects.

    cheers

    ReplyDelete
    Replies
      Reply
  13. MiskoJuly 14, 2008 at 7:14:00 AM PDT

    For people who think that this article does not apply to dynamic languages (as some of you pointed out in the comments) I would like to point to: http://www.testabilityexplorer.org/blog/2008/07/13/dynamic-languages-are-not-more-testable

    ReplyDelete
    Replies
      Reply
  14. Michael FoordJuly 14, 2008 at 7:31:00 AM PDT

    @Misko

    Most of the points you make in your "dynamic languages are not more testable" seem to be based on a misunderstanding of the testing techniques used in dynamic languages.

    Patching global state is dangerous - but can easily be localised to within the body of a single test method (e.g. by a decorator in Python). You are right that it makes parallelising tests harder - personally I prefer to parallelise tests across several machines though (or use multiple isolated interpreters to parallelise which also avoids the 'global' problem).

    More to the point, mutating global state (class level attributes) is only one small technique - more importantly you can patch *instance* methods without touching the class at all, and can trivially use mocks without having to jump through hoops (duck typing rather than static typing).

    Dynamic languages are *significantly* easier to test - for many reasons.

    ReplyDelete
    Replies
      Reply
  15. Efrain SteinbachApril 8, 2011 at 9:04:00 AM PDT

    I really don't get this. Why can't I just have a 'new' command in the House's constructor? That's what the constructor is for in my understanding of object oriented design.

    In my test environment I then just swap out the Kitchen and put in a Mock Kitchen:

    House myHouse = new House();
    myHouse.kitchen = new Mock();

    .. I may be completely wrong, I'm a noob to unit testing.

    ReplyDelete
    Replies
    1. UnknownAugust 21, 2013 at 10:06:00 AM PDT

      The benefit of dependency injection becomes obvious if the Kitchen is really expensive to instantiate, and especially if it is not strictly needed for all your tests of House. In fact, it should not be needed at all and should be tested in a separate test fixture. The collaboration between classes are integration tests and should not be part of unit tests.

      Another scenario would be if you have a dependency that communicates with a slow data source (e.g. a remote database). You would rather inject a mocked database provider. This would also benefit from using interfaces to separate interface from implementation, which is not covered in this article.

      Delete
      Replies
        Reply
    2. Reply
  16. Jon AustenOctober 19, 2015 at 10:06:00 AM PDT

    Loved the article. Doesn't say anything about how you should test the Factory class though...

    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