Summarized using AI

Why You Don't Get Mock Objects

Gregory Moeck • September 29, 2011 • New Orleans, Louisiana • Talk

In this presentation at RubyConf 2011, Gregory Moeck discusses the misconceptions surrounding mock objects in testing, particularly within the Ruby community, which has historically viewed them with skepticism. He addresses the reasons why many Ruby developers are resistant to using mock objects, emphasizing the lack of understanding regarding their purpose and benefits.

Key Points Discussed:

1. Understanding Mock Objects:

- Mock objects are often criticized for duplicating implementation and leading to brittle tests.

- This criticism is mainly due to a misunderstanding of how mock objects work and their intended use in enhancing testing and design.

  1. Procedural vs Object-Oriented Programming:

    • Using mock objects effectively requires a shift from procedural programming to object-oriented programming principles, particularly the 'Tell, Don’t Ask' principle.
    • Mocking is a good practice in OOP where messages between objects are emphasized rather than the internal state.
  2. Key Principles of Mocking:

    • Mock Roles, Not Objects: Mock objects should represent roles rather than concrete implementations to help improve the design.
    • Only Mock Own Types: Developers should only mock objects they control to avoid testing implementation rather than behavior.
    • Mock Peers, Not Internals: It’s crucial to identify what belongs inside versus outside of an object; mocking internal details can lead to fragile tests.
  3. Examples and Illustrations:

    • Moeck provides examples comparing good practices in mock object usage versus poor approaches, such as using mocks for boundary objects like APIs.
    • He illustrates how to implement these principles with Ruby code examples that show the advantages of mocking appropriately without duplicating logic.
  4. Conclusion and Takeaways:

    • The use of mocks can enhance design quality and testing efficacy if applied correctly.
    • Developers are encouraged to adopt a mindset that focuses on roles in their systems, leading to decoupled and maintainable code.
    • A recommended resource is the book "Growing Object-Oriented Software, Guided by Tests" as a comprehensive guide on effective testing practices using mocking principles, despite its Java context.

Why You Don't Get Mock Objects
Gregory Moeck • New Orleans, Louisiana • Talk

Date: September 29, 2011
Published: December 12, 2011
Announced: unknown

Although the Ruby community has embraced TDD like no other community ever has, we have always looked at mock objects with disdain, and perhaps even a little hatred. I've heard conference speakers call them "Wastes of time", "Scams", and even "Testing Heresies". Why would anyone have ever developed these pieces of junk? In reality though many in the agile community have embraced mock objects within their testing cycles because they have found using these fake objects improves the design of their systems. But why not Rubyists? Most Rubyists don't get mock objects because they don't understand their history or their creators intent. They try to fit them into their current workflow without understanding them, and find them unhelpful and stupid. After all, almost all of the good literature on the subject is written in Java, and we know how frustrating it is to read Java when your used to Ruby. As such, this talk will attempt to demonstrate in Ruby the usefulness of mock objects, and how to use them to improve the design of your system. Specifically the following will be covered: * Why do we need mock objects (Following the 'Tell, Don't Ask Principle') * Why you should only mock objects you own * Why you shouldn't use mocks to test boundary objects like external API calls * Why you should mock roles, not Objects * Why you should only mock your immediate neighbors * Why listening to your unit tests will tell you about design problems in your code

RubyConf 2011

00:00:17.080 all right afternoon everybody my name is uh Greg Mech I work for a company called strobe and uh they sent me here so I
00:00:24.000 wanted to just Express a bit of uh gratefulness to that and also tell you that uh if you got guys are building any
00:00:31.359 JavaScript application that is talking to a backend um just basically as an API I would
00:00:38.239 encourage you to check out strobe it basically allows you to deploy the application to the web Android and iOS
00:00:45.000 just with a simple uh strobe deploy command so check that out if you want
00:00:51.039 and uh this afternoon I guess it's still morning I'm going to be talking about why you don't get mock
00:00:58.399 objects so first first uh matter of introduction a little bit about
00:01:04.159 me first thing you need to know is that I am not a primary teacher now you might
00:01:09.560 wonder what the heck is that but I am a secondary teacher let me explain what I
00:01:16.360 mean by that there's a quote from uh Mortimer Adler in his book how to read a
00:01:21.439 book where he says this the secondary teacher should regard himself as learning from the Masters along with his
00:01:27.840 students he should not act as if he were a primary teacher using a great book as if it were just another textbook of the
00:01:34.600 sort one of his colleagues might write he should not mascarade as one who knows and can teach by virtue of his own
00:01:40.960 original discoveries the primary sources of his own knowledge should be the primary sources of learning for his
00:01:46.560 students and such a teacher functions honestly only if he does not aize himself by coming between the great
00:01:52.960 books and their readers he should not come between as a nonconductor but he should come between as a mediator as one
00:02:00.039 who helps the less competent make more effective cont contacts with the best
00:02:05.119 Minds so when I say I am not a primary teacher but rather a secondary teacher I mean this I am not an expert on mock
00:02:12.480 objects in the sense that I develop them or come up with anything new basically in this talk basically everything I'm
00:02:18.720 going to say is something that somebody has said before probably better than me the only difference is that they
00:02:24.800 probably said it in relation to Java
00:02:30.319 this is uh the book that I think is probably the best book on mock objects and if you haven't read it you really
00:02:36.879 should go and get it it's called growing object-oriented software Guided by tests by Steve Freeman and Nat price these
00:02:43.560 guys are the primary teachers I'm just going to try to bridge the context today into
00:02:49.720 Ruby secondly let's talk a little bit about mock objects now the Ruby Community plus mock
00:02:56.599 objects equals what love
00:03:02.720 uh no not really mock objects have been called the
00:03:08.040 following inside of the Ruby Community wastes of time if you are using mock
00:03:13.560 objects you are wasting your time they have been called scams it's like somebody's trying to
00:03:19.239 pull the wool over your eyes and my personal favorite testing
00:03:26.120 heresies if you are are using mock objects you are a heretic and you deserve to be burned at the stake okay
00:03:32.200 maybe not quite that strong but still that seems to be the general reception
00:03:37.959 within the Ruby Community now why is that generally people give two reasons
00:03:44.560 as to why they don't like mock objects the first being that they duplicate implementation so here is an rspec
00:03:51.799 example from a talk that was given at Ruby comp in 2008 and you have uh describing a show
00:03:58.680 controller and it says when a TV show has no public videos it should not
00:04:03.720 display any shows and in order to do that it uses should receive all on the
00:04:10.439 show object with select ID name video count condition shows. video count
00:04:16.840 equals z and return an empty array and then it does the rest of the test and
00:04:22.240 then you come to the implementation and oh look show all
00:04:27.639 select ID name video count count conditions shows video count greater than zero you see that part right
00:04:35.880 there is exactly duplicated in the
00:04:41.039 implementation and they say well this is stupid if I want to change anything about this I'm going to have to change
00:04:46.680 both the tests and the implementation I'm just duplicating the system under test seems pretty bad
00:04:54.320 huh second I've heard it argued that it leads to brittle tests that do a poor job
00:05:00.840 so for example uh this is from the arpec book written by David chelimsky uh and
00:05:06.520 it's describing a codebreaker game and it says when the game starts it sends
00:05:12.320 the welcome message and in order to be able to do that it provides a mock object doubles as the output it says the
00:05:19.280 output should receive puts with welcome to codebreaker and then it says game.
00:05:25.960 start and then you come into the actual implementation and and you've got the same sort of thing output puts welcome
00:05:32.560 to code breaker but imagine we were to refactor this instead of using
00:05:38.880 puts we use wrs that would be the same from the end user perspective and yet guess what
00:05:46.080 happens if you change that the tests fail oh wow that's stupid I mean the end
00:05:52.960 behavior is the same why would I ever use these the output doesn't change QED right right end of story mock
00:06:04.600 suck well maybe or maybe you just don't understand
00:06:11.840 them in fact actually uh there was a talk that I was G going to give on a
00:06:17.199 clean arpec at the LA Ruby uh Meetup and I was going to slam on mock objects
00:06:23.440 pretty bad because I thought that they did exactly these sorts of things and then I stopped and I said
00:06:31.039 this is this seems so obvious if this is how mock objects are supposed to be used why would anybody
00:06:38.520 ever have invented these pieces of junk and I said okay well maybe I just
00:06:44.240 don't understand them so I'm not going to slam on them until I understand them
00:06:50.400 which by the way just a piece of practical advice is usually a pretty good idea
00:06:59.800 when smart people invent something and then you think hey man this is so
00:07:05.960 stupid don't say that to anybody until you actually understand it
00:07:12.840 then if you want to declare it stupid that's fine but make sure you understand it before you start talking or you're going
00:07:20.199 to end up looking like a fool okay so why then would we use mock objects let's talk about that a little
00:07:27.840 bit the first thing I want want to say is that mock objects plus procedural programming is a bad
00:07:34.199 idea almost always first thing related to that mocks are not
00:07:40.319 stubs now I hear a lot of people talk about well I'm just going to mock out that object because mock objects are the
00:07:46.599 way that people generally have done that but there is a subtle distinction between what is a mock object and what
00:07:51.720 is a stub mocks assert on messages that go between objects whereas stubs return a value
00:08:01.159 so a stub is going to say when you call this method give this value back so that I can assert on some state within the
00:08:07.800 object a mock is actually designed to get in between the two objects and allow
00:08:13.319 you to assert on the message going between the two so for example here in this show
00:08:19.120 controller this part right here is really a stub now there is an
00:08:24.280 expectation on it because it has a should receive but the point is that
00:08:29.840 when I call this method I want it to return an empty array so that I don't have to talk to the database or whatever
00:08:36.039 and you can tell that this is actually a stub and not a mock because you're actually asserting
00:08:41.360 on the body it's asserting on state when you're asserting on state you're stubbing when
00:08:48.160 you're asserting on messages between objects you're mocking so mocking plus procedural
00:08:55.600 programming is a bad idea but mocking plus oop is a good
00:09:01.120 idea so the key idea in object-oriented programming is objects tell objects to
00:09:07.640 do things now I know we don't write our code this way a lot inside of the Rails
00:09:12.920 community at least but I think we're moving in that direction a little bit there's been a lot of chatter on the
00:09:18.200 blogosphere and on like the Ruby Rogues podcast lately about moving towards objectoriented programming more of a
00:09:24.720 tell don't ask sort of style and uh this is uh what Allan K had to say about
00:09:31.120 object oriented program how many of you know who Alan K is okay that's encouraging for those of
00:09:37.600 you who don't he's the inventor of small talk and kind of the guy who coined the idea of object-oriented programming to
00:09:44.120 begin with and he says this the big idea of object-oriented programming is
00:09:49.720 messaging that is what the kernel of small talk or squeak is all about the
00:09:54.839 key in making great and growable systems is much more to design how it's mod modules communicate rather than what
00:10:01.839 their internal Behavior should be so for example this might be uh
00:10:07.680 internally what your system would look like the circles represent objects and
00:10:13.440 the arrows in between are the messages that they send hey do this hey do this hey do this and what Alan K is saying is
00:10:20.800 that the key important thing in growing objectoriented systems is not to worry
00:10:26.320 about what is contained inside of the objects but but to worry about the messages that go between them that it is
00:10:33.760 inside of the messages of an object-oriented program that the meaning or the uh domain logic of the
00:10:41.720 application is truly found so for example to change the
00:10:47.079 behavior of a system we compose objects instead of modifying methods so let's
00:10:54.000 look at a contrived example see if we can see what what I have in mind here imagine that you have have a ticket
00:11:00.120 machine interface maybe it's like an ATM you've got a bunch of buttons and you're going to type in the number of tickets
00:11:05.680 that you want to use then you're going to push submit okay and you've got this ticket
00:11:10.720 machine object and you've got a ticket reserving system you're going to say hey
00:11:17.000 I pushed you know this number and then this number then I pushed submit and it should Reserve those uh tickets for me
00:11:26.800 imagine if you wanted to save the request before sending them okay you have this
00:11:32.000 object it manages the interface you want to save the request maybe to a database or something before you send the
00:11:39.320 request in procedural programming how would you do that well you'd go to the method that does it and you would add
00:11:45.800 code to that method you would insert okay before you do this you're going to
00:11:51.480 add this code and then you can do what you were doing before whereas object-oriented programming says once an
00:11:56.600 object is complete and it does what you want it to do in order to modify Its Behavior you shouldn't have to change
00:12:02.480 the object itself you just change the object composition so for instance you
00:12:08.600 have the ticket machine interface and it still is reserving tickets but you put another object in
00:12:16.399 between the two objects to persist the ticket requests and then it calls the
00:12:21.920 same API on the ticket Reserve System and this enables you to not have to
00:12:27.040 change the code that you already know is working you just change the composition of the
00:12:33.160 objects so what would code for this interface look like maybe something like
00:12:39.639 this you have the ticket machine interface on initialization you have a request Handler and you store the
00:12:45.839 current display when a number is pressed you add that number to the current display when delete is pressed you drop
00:12:52.959 off the last number that went on and when you submit the request you tell the request Handler to reserve a current
00:12:59.800 display to I to those of you who are are not used to working in more of an O style this might be a little weird but
00:13:05.560 this is basically how tell don't ask well-encapsulated code
00:13:11.680 works and there are two things that you want to notice about this first it follows the tell don't ask
00:13:19.040 principle notice everything is being the object is being told things hey this
00:13:25.440 number was pressed delete was pressed submit this request so it's following
00:13:33.160 tell don't ask it's not asking for information out of the objects in order to make decisions based off of that
00:13:38.839 information that it gets back it's telling the object certain things have happened or to do certain
00:13:44.560 things second notice that it hides its internal State what is the internal State
00:13:51.519 here it's that current display whatever is currently being displayed is what
00:13:56.560 this object is encapsulating and hiding data for and notice that there are no
00:14:01.880 Getters on this object there's no way really to get at this current display
00:14:08.120 except in Ruby this actually does return the thing right but it's supposed to be a command not a
00:14:14.680 query and so now all of a sudden we've got this internal state that is
00:14:20.000 completely hidden and we have no ability to access it which leads to a question
00:14:26.399 how could you write a unit test for this code
00:14:31.839 usually when we do tdd we think of it in terms of I call an API it's going to change the state on the object and then
00:14:37.399 I'm going to assert that this state is now this that it did what I expected but if I'm hiding all of the internal
00:14:43.959 implementation of my code how would I test this can you assert on the state no
00:14:50.320 you don't have access to the internal State and by the way that's a good thing if you don't think it is you should read
00:14:56.040 up on information hiding it allows you to build complex apis that you don't have to know the implementation of all
00:15:02.079 you have to know is its API in order to be able to use it it basically becomes a black box an
00:15:08.160 abstraction all of us expect that of our libraries can you imagine a library that you had to know the internal details in
00:15:14.759 order to be able to use it but we don't generally expect that of our own code base but when we start moving in that
00:15:21.959 direction hiding the internal implementation of the object we no longer can see its internal State we can
00:15:27.480 only see what it does and so how would we unit test this well one method that's
00:15:33.120 been proposed is just add Getters for the tests I don't really think that's a good
00:15:38.360 idea because when you start modifying and adding special paths into your code
00:15:43.759 just in order to be able to test it you're not actually operating on the
00:15:48.880 path that your code is going to run in production it seems bad to me so then how would you do the
00:15:55.000 test well remember this is kind of our picture we have this ticket machine interface and these objects are telling
00:16:00.839 each other to do things so what if instead of actually using a real ticket Reserve System I replaced that ticket
00:16:08.079 Reserve System oh I guess I don't have the ability to get
00:16:14.199 into the test but I can assert on the message going between the tests kind of
00:16:19.839 like Alan K said the key thing is the messages going between and so I can assert on the message that the ticket
00:16:25.920 machine is telling the ticket Reserve System so how would I do that well
00:16:31.519 instead of re re using a real ticket Reserve System I'm going to replace it
00:16:36.880 pass it into the Constructor with a fake object and this fake object is what we
00:16:42.399 call a mock object and so my test would look something like this my request
00:16:49.600 Handler should receive Reserve with 55 and you see I'm passing that that
00:16:56.319 request Handler in in the place of that ticket Reserve
00:17:02.720 System you see I'm replacing it with a mock object a fake and the the the
00:17:08.720 responsibility of this mock object is to record every message that is sent to the object so that I can then assert on
00:17:15.959 those messages that were sent and so I I say hey mock object this
00:17:21.880 is my assertion you should receive the message Reserve with these parameters
00:17:28.240 passed to it and that's the assertion on the message
00:17:34.559 going between the two objects and then I call the public API I
00:17:40.400 pressed five and then I pressed five again and then I pressed the submit
00:17:45.440 button and that should send the message Reserve with the number
00:17:52.480 55 here's the key idea o in oop behavior is found in the messages
00:17:59.880 and so we don't want to assert on the state of an object we want to assert on the messages going between the objects
00:18:06.960 and in order to be able to do that we replace real objects with fake objects or mock objects in order to be able to
00:18:13.600 assert on those messages okay so having said that then
00:18:20.520 it takes a little bit of a change of mindset in the way you do programming honestly if you just are doing a rails
00:18:27.120 application that you are doing things procedurally odds are mock objects are not for
00:18:32.960 you it's kind of like this okay if you wanted to bang a nail into a piece of
00:18:40.200 wood you want to use a hammer a screwdriver might
00:18:45.280 work but a screwdriver is not designed to bang in the nail you want to use a
00:18:50.720 hammer which is generally assertions on state when you're doing a more procedural flow when you are hiding your
00:18:56.320 information encapsulating it and telling other objects to do something then you pull out the tool called the mock object
00:19:03.320 because that's what they're designed to be used for so let's talk a little bit then
00:19:09.240 knowing that about some key mocking rules and I'm taking all of these from
00:19:14.320 Steve Freeman and Nat price over the years so again I am completely not
00:19:19.400 unique or interesting the only difference is is that I'm using Ruby whereas they are using
00:19:24.880 Java so the first rule is mock roles not objects what do I mean well here's the
00:19:32.360 paper that they wrote for oopsa in 2004 if you want to look it up that's actually entitled mock roles not
00:19:39.840 objects and the basic gist is wanting to mock concrete objects is a design
00:19:47.880 smell that is it's telling you the implementation of your actual code has a
00:19:55.480 problem why because well-designed objects don't know explicitly who they
00:20:00.520 are talking to why because who they are talking to
00:20:06.480 can change they should only know the role that their collaborator is
00:20:12.840 playing not the concrete object which they are talking to so for example in
00:20:17.919 our ticket machine interface this role on the right side
00:20:22.960 that the ticket Reserve System is playing is may be called the ticket machine request Handler it handles
00:20:29.200 requests from the ticket machine the ticket machine doesn't need to know that it is particularly talking to a real
00:20:35.919 ticket Reserve System and in fact if you know that you're talking to a real ticket Reserve System you can't do
00:20:41.760 something like this you see now I've changed the composition of the objects and now
00:20:49.120 instead of the ticket Reserve System playing the role of the ticket machine request Handler my persist ticket
00:20:57.400 requests object is playing the role of my Reserve or my ticket machine request
00:21:03.440 Handler and from the perspective of the ticket machine I need to not care what the actual object is doing
00:21:10.679 when I send it the message all I need to know is what are the roles that the potential collaborators are playing so
00:21:17.360 that I can tell them to do something and then let them carry out their things and so when mocking rolls tdd
00:21:25.600 becomes a design process not merely about asserting that the behavior is
00:21:31.600 correct although it does that too it becomes a question of what are the roles
00:21:37.679 that my collaborating object should be playing that is what doesn't belong internal to my object so for example if
00:21:45.600 I start with just a ticket machine interface and presumably I have you know come to this interface through some form
00:21:52.799 of tdd so I already know what role it's playing because I know that there's
00:21:57.919 going to be an object sending messages to it so I start with this I know it's going to have number pressed delete
00:22:03.760 pressed and submit request what do I do well I'm going to come up with a
00:22:10.799 scenario that is going to demonstrate the domain logic of this Behavior it reserves the correct number of tickets
00:22:17.360 when a number is pressed two times before submitting and I would say okay here's a scenario kind of like what Jim
00:22:22.440 was talking about earlier given a ticket machine interface when I press five
00:22:29.440 twice which is machine number pressed five times and then I submit the request
00:22:35.159 what would be the proper behavior and then I ask myself okay does
00:22:40.520 this behavior that it's supposed to do is it supposed is is this really behavior that belongs inside of my
00:22:46.559 ticket machine interface if it's following the single responsibility principle an object
00:22:52.080 should have one and only one reason to change I don't want to actually put the logic for handling the request
00:22:59.279 in the same place that I'm going to put the logic for handling the interface
00:23:05.039 those belong to two separate things and so I okay I say okay what is the role
00:23:10.240 that the collaborating object here needs to play well I need whatever object I'm
00:23:16.799 going to tell to handle a request when I am ready to send one and so I create a
00:23:23.640 mock object not an actual object that is going to be implemented but a role that
00:23:30.840 that object is going to play particularly here it's the request Handler and I'm going to say okay what
00:23:36.919 Behavior should I tell this object to do I should tell it that it needs to
00:23:43.640 reserve 55 tickets because I pushed 55 twice and then I told it to submit the
00:23:51.440 request and then I come back and I say okay I have this role so I need to pass
00:23:56.960 it into my Constructor I add it to the Constructor and I know I'm going to submit my request I'm going to do re
00:24:03.600 request Handler reserve and I'm going to need to send it whatever the current display is now this should start to feel
00:24:09.440 like tdd to you hey wait a second okay I'm sending the current display but I'm
00:24:15.120 not doing anything with the current display yet so if I want to get it to actually send the right message I have
00:24:21.880 to implement the number pressed API so that it is storing whatever the current display is as it goes along and so I add
00:24:28.919 an internal State current display and I say number pressed when that happens add
00:24:34.480 that to the current display and when I send it I want it to be an integer by the way you'll notice this is
00:24:40.720 not complete code because if I were to just immediately push submit request what's it going to send an empty string
00:24:47.120 to I guess I need more test cases right but you see this is the same sort of
00:24:52.200 thing in the way that you do tdd normally the only difference is you are asserting on a message instead of
00:24:59.399 asserting on the state of the object and what you end up doing is you
00:25:04.840 end up getting a more decoupled system because now you're talking to a role and you're following this it helps
00:25:12.080 you to follow the sing Single inter or the single responsibility Principle as well as a bunch of the
00:25:18.399 other solid design techniques so the first thing is mock
00:25:24.559 roles not objects the second rule is only mock types that you own now in
00:25:32.080 Ruby we don't really have types but the idea I think still holds here's uh two references I put
00:25:39.200 these in primarily so that if you want to look at the slides afterwards you can look them up and here's the basic rule
00:25:45.159 if you don't own the API there is no design feedback that you were going to get by writing a test for
00:25:53.640 it instead of mocking a role what you are really mocking is an
00:25:59.000 implementation because you don't own the API and you can't form it into whatever the role is going to be
00:26:05.760 played and so what you end up doing is you end up duplicating your production code in your test which is a test smell
00:26:16.080 that doesn't mean you should never do it right it just means when you smell it you should go H do I really need to do
00:26:24.120 this and so this means don't mock boundary objects what do I mean by that
00:26:29.520 here's the example that we talked about earlier in relation to the Codebreaker game from the rspec book and by the way
00:26:36.320 when uh this came up on a Blog Dave chelimsky actually said that this is the
00:26:42.320 way you should do it so I'm I'm not necessarily critiquing David um but here
00:26:47.720 is the example right and inside of the code breaker
00:26:53.000 game what you're doing is you are sending a message to
00:26:58.919 puts right there and we're sending the message output to
00:27:05.360 puts what's the problem with that well we're coupling that to the actual
00:27:10.640 standard output we're saying the responsibility of this game is to talk to a command line
00:27:17.320 interface so it's specifying more than it needs to it's handling the starting of the game as well as specifying what
00:27:24.720 the object it is talking to is instead of specifying a role so what would we do
00:27:30.880 instead we would mock the RO in the domain object so for example instead of calling
00:27:37.360 it output we might call it displayer and we would pass in that
00:27:42.760 displayer and we would say the displayer should receive display with welcome to
00:27:48.559 code breaker and we would do the same thing in the actual
00:27:54.399 code we would implement the display object using then puts whatever the role
00:28:00.159 that we're playing would then use puts you might be thinking how is this any
00:28:05.840 better isn't this just changing words I mean you playing semantic games with me
00:28:12.320 no I think it actually is better because say for example you want to move from
00:28:17.679 using a command line interface to using a rich guey should you have to change your game
00:28:25.080 object in order to change from a command line interface to a rich goey no because
00:28:33.559 that object is really just a role it's the the role that it's playing is displaying the information the fact that
00:28:40.760 it's using puts is an implementation detail specific to how you display the
00:28:46.360 object or display the state as opposed to the actual game itself so we should
00:28:52.080 separate concerns that way we could switch the object if we wanted to to to move to a
00:28:59.320 guy instead of using the command line puts we would implement it doing something else and the game object
00:29:05.720 wouldn't have to know the difference so what about testing the display
00:29:11.120 object it's like am I just getting into a problem that this is going all the way down well the Steve Freeman Nat price
00:29:18.960 the guys who are are heavy into the London School of tdd actually say no in
00:29:24.279 those cases you should not write unit tests you you should not isolate that object instead you should write what
00:29:31.120 they call integration tests integrating with an outside system or if it's simple
00:29:36.399 enough like it probably is in this case you can leave it to your acceptance
00:29:41.519 tests right you could write an end to end acceptance test using something like AR Ruba to test the command line
00:29:48.519 interface and it's going to verify that that code on the edges of your system is actually doing the right thing and the
00:29:55.840 reason why they say that is because if if you are mocking an object that you don't own you don't get any design
00:30:01.360 feedback it's not representing a role inside of your system and so necessarily
00:30:06.440 you will have to couple that object or couple that message that you're sending
00:30:12.159 to the implementation of how you are currently using it instead we want to keep that implementation outside of our
00:30:18.120 domain objects and test those borders independently in integration test if you
00:30:24.120 need to or just let your acceptance tests handle it okay last
00:30:29.519 principle uh mock peers and not internals this is another thing that
00:30:35.159 gets people into a lot of trouble it's something that actually has only begun to be articulated a little more recently
00:30:40.960 mock objects have been around I think since the 90s uh I think that this distinction only came about in the
00:30:46.039 growing object-oriented systems Guided by testbook that I talked about and those are two references and the basic
00:30:52.720 idea is this you need to decide what is inside and what is outside of your
00:30:58.440 object when tdd becomes a design process you have to ask yourself does this
00:31:05.799 implementation that I am talking about belong internal to my object or as a
00:31:11.919 collaborator of my object and the key thing to notice here is that not everything belongs to a you
00:31:19.919 can't just infinitely delegate things out there has to actually be some domain logic contained inside of your domain
00:31:26.760 objects and and not everything inside of there if you use objects has to be
00:31:32.240 mocked out the key question you want to ask yourself when you're thinking about do I
00:31:39.039 push this outside of my object or do I stay inside of my object is is this implementation that I'm doing is this
00:31:46.720 the role that I am supposed to play as object XYZ if it is my role then I'm going to
00:31:54.720 make that internal to my object even if I use other objects and I am not going to mock that because
00:32:01.880 that is going to be an implementation detail of how I play the role that I am going to play so for
00:32:08.840 example um this is I'm actually taking out of the growing objectoriented systems Guided by testbook they actually
00:32:14.720 build a a whole uh auction bidder uh for you and this is one of the beginning
00:32:22.360 parts of the uh system they have an auction server that sends messages in
00:32:27.960 into the system and it's sending it in you know some form of a string coming down over a socket I believe and it
00:32:34.000 calls process message on this auction message translator object and the role
00:32:39.480 of this auction message translator is to translate the message that comes in from
00:32:44.679 this string into the language of the domain that is different types of
00:32:51.399 messages come in and the translator translates them into domain terms into
00:32:56.919 the way that it talks to the apis internal to the system and so this would look something like this describe
00:33:04.120 auction message translator it notifies bid details when a current price message is received and it has a role of an
00:33:12.039 event listener and it says The Listener should receive current price with 192
00:33:17.919 and seven that 192 is coming from the current price and the Seven is coming
00:33:24.679 from the increment how much it changed by the basic idea is this is coming down from the server in a string but when
00:33:31.440 you're working internal to your objects you don't want to have to know about that string all you care about is
00:33:36.760 whatever the current price is and whatever the increment is and so the way
00:33:42.120 that they do this is they say the message translator when it receives a message with so version 1.1 event price
00:33:50.000 current price 192 increment 7 bitter someone else should send a message into
00:33:55.600 the system saying the current price is now 192 and changed by
00:34:03.799 seven make sense and then the way that they do this
00:34:09.480 is they have an auction message translator that processes the message by
00:34:14.919 saying unpack event from this message if the event type is closed you're going to
00:34:20.440 send the message auction closed if the event type is not closed send the
00:34:26.440 current price with event current price and event. increment that's pretty
00:34:31.720 semantic I think inside of in inside of the process message but the key thing to notice how do they do that well unpack
00:34:39.720 event creates a new object called the auction
00:34:45.560 message event and passes in the string and then they create a nice API that
00:34:50.639 they're going to work with so that they can just say event. type instead of having to extract that out of the string
00:34:58.400 and they can say event. current price event. increment this is essentially
00:35:03.599 creating an immutable value object from the string that came in from the
00:35:10.160 server but you'll notice if we go back and look at the tests there is no
00:35:15.560 mention of this object this auction message event they're not stubbing it
00:35:22.320 they're not mocking it why because it's an in internal object
00:35:29.359 it's an implementation detail about how they are doing what they are doing instead of what they are doing and so
00:35:36.960 not every object needs to be mocked not every object needs to be stubbed don't mock this don't stub it why because it's
00:35:44.359 an implementation detail as that string changes the thing might change and you
00:35:50.760 end up getting very brittle tests when you start stubbing these things it's
00:35:55.839 better to just execute the code as a black box and when it changes or when uh
00:36:03.040 when you know the requirements change you add more tests you change the inside but the tests don't need to know about
00:36:08.520 it the tests respect the encapsulation of your code and test it from the outside of the system not
00:36:16.400 inside okay so further resources I'm going to tell you there is one that I
00:36:22.400 would recommend anybody who is interested in this pick up and it's growing object-oriented software Guided
00:36:28.079 by Tess yes it is in Java but you know Java in many ways is
00:36:34.359 the lingual lingua franka of a lot of object-oriented design and a lot of uh
00:36:42.079 tdd a lot of this was developed inside of java and if we're going to be Craftsmen if we're going to be
00:36:47.280 professionals we need to learn to read Java even if we don't write
00:36:53.920 Java so I would recommend highly that if you're interested in this pick up this book uh I learned a huge amount of
00:37:00.560 things by reading it through and I think that uh that's about
00:37:06.200 it there any questions how would you recommend tell
00:37:12.800 me if thiss into Des we have aent who an API we not have
00:37:20.520 to it but we need to know U we don't want to have to actually hit the API for
00:37:26.160 real you that would be a good case to use a to say when we give them this
00:37:31.280 message we expect this response for them so I think the key thing to to notice um
00:37:39.119 is you're not really doing a command there uh you said uh when we send it
00:37:44.520 this message it gives us this back so that isn't really a mock that's a
00:37:50.280 stub um and so we want to be careful with where we use stubs because we are coupling it to an implementation but I
00:37:56.680 think that one legitimate use case to use stubs is so that you don't hit a real server um I do find it helpful to
00:38:03.400 at least have some tests that run against the real thing though so that I know if they broke it uh generally those
00:38:08.839 I would consider like integration tests
00:38:35.960 so you can definitely feel the notion of a role inside of an interface um Steve
00:38:42.040 Freeman though has a lot of his original background is in small talk which is uh
00:38:48.520 where a lot of the design philosophies originated um the way I tend to think
00:38:53.960 about it is my mock objects are actually defining that
00:38:59.880 interface um and so even though the language construct does not exist I
00:39:05.760 don't view that necessarily as a bad thing because I think it actually is a little cleaner inside of java you have
00:39:12.280 to specify that interface both in your production code and in your tests and so
00:39:18.079 you end up having to refactor both your uh production code and your tests when you want to change the the role uh or
00:39:25.319 the message maybe for design reasons or for whatever I find that to be actually a little easier and clearer to do in a
00:39:30.640 dynamic language because then I only have one place where it actually is specifying that role which is inside of
00:39:38.000 my tests are
00:39:44.800 youself now am I yeah so uh my design style has become
00:39:54.400 very mock driven um I I think I would subscribe to what
00:39:59.960 Michael feathers calls the London School of tdd uh because I found that it produces a better design system it
00:40:06.520 doesn't mean I mock everywhere uh there are some places where it makes sense to do assertions on state as opposed to
00:40:13.040 doing assertions on uh instead of doing assertions on the
00:40:19.000 messaging between the objects on behavior um so like maybe if if that uh
00:40:26.599 if that underl object which is an internal peer uh the logic became very complex and I wasn't satisfied with just
00:40:34.560 treating it like a blackbox I might write unit tests for that object um that
00:40:40.440 just tested the responses coming out of it and I would use state for that but generally I tend to to think
00:40:48.200 much more in a tell don't ask style uh can you talk a little bit about
00:40:55.599 how you do this when reflector when you have a class that's overload with responsibilities extract that
00:41:03.319 out sure um so one of the things that is is
00:41:09.040 difficult is when you come into I guess I should repeat the question the question is how
00:41:15.920 would you refactor something from using heavily state-based uh tests to a more
00:41:22.520 mock based uh test um and I think think
00:41:28.000 it can be challenging uh because you're not just changing the way you test you are
00:41:34.520 changing the way that um you're changing the internal entire internal
00:41:40.599 implementation of your code it's kind of like you're going from a procedural oriented um place where you're getting
00:41:47.760 information and then making decisions based off of that information to a telling um the thing that I find to be
00:41:53.000 the most helpful is actually having an end to end test Suite something like cucumber or some acceptance tests that I
00:41:59.560 can turn off the unit tests and try the refactor like rewriting it
00:42:05.960 um the other the other resource that I might point you to is uh Michael feathers book um dealing with Legacy
00:42:12.880 code doesn't address that topic directly um but he talks about how would you
00:42:18.440 inject an interface um in his purpose it's it's kind of sprouting an object for
00:42:24.599 uh for cleaning up Legacy code being actually able to test but I find some of
00:42:29.640 the same techniques apply um you just have to be careful breaking the
00:42:36.880 dependencies any other questions in your example you
00:42:44.520 use display object that you made instead of put inside your class when would you just straight up go with puts inside
00:42:51.280 your class or should you always create a object sure so the question is uh in my
00:42:56.440 example I uh created an object to do the display instead of uh just using puts
00:43:03.400 inside of the object when would I make an object versus just using puts inside
00:43:09.240 of the object um I think the answer to that question for me generally is
00:43:14.559 whenever I would write tests for it um something that is simple enough and small enough of a program that I don't
00:43:22.640 have I'm not worried about maintaining it it's just a script I would put those things inside of an object
00:43:27.839 uh I probably wouldn't write unit tests for it I might write an end to-end acceptance test and just kind of treat
00:43:33.200 the whole system as a black box uh but when I personally get into the situation
00:43:38.640 where I know I'm going to incrementally build this system over time and I'm going to have to maintain this I'm going
00:43:45.240 to want to have a strong separation of concerns and stuff like that that's when I would do the the sort of mock create
00:43:52.359 an object all right well if you have any
00:43:57.559 other questions feel free to come and talk to me thank you very much for coming
Explore all talks recorded at RubyConf 2011
+55