Summarized using AI

Better code through boring(er) tests

Betsy Haibel • June 22, 2017 • Singapore • Talk

In her talk titled "Better code through boring(er) tests," Betsy Haibel, a seasoned developer, discusses the importance of testing within the Ruby on Rails community during the Red Dot Ruby Conference 2017. She explores the common complaints developers have about tests and offers practical solutions to improve both tests and application code.

Key points of the presentation include:
- Understanding Test Discontent: Developers often perceive tests to be burdensome due to their own imperfect understanding while writing both application code and tests. Recognizing this complexity can help alleviate the negativity surrounding tests.
- Test Smells Identification: Haibel identifies three 'test smells'—testing private methods, duplicate tests, and unnecessary complexity—which contribute to test failures or frustrations. She emphasizes the importance of addressing these issues to stabilize tests and code.

- Improving the Testing Process:
- Testing Private Methods: Rather than directly testing private methods, Haibel suggests making these methods public or properly structuring code to avoid direct testing while still ensuring adequate functionality.
- Handling Duplicate Tests: To reduce redundancy, she encourages improving application code rather than mirroring test structures directly, outlining that shared functionality should be encapsulated properly in code.
- Combatting Complexity: Haibel discusses the pitfalls of overly complicated test setups (referred to as 'inventing the universe') and advocates for simplicity. The use of factory methods and judicious extraction of complex logic into the application layer are recommended strategies.
- Boring Tests Lead to Better Code: By iterating towards simpler, more boring tests, developers can gain clarity on their code's intent, allowing for better understanding, maintainability, and future refactoring.
- The Context of Boring vs. Clever Code: Betsy reflects on how defining what is 'boring' can vary across teams and projects, ultimately emphasizing that clarity and simplicity should take precedence over clever coding tricks that obfuscate intent.

In conclusion, Haibel encourages developers to embrace the inherent complexities of their code while striving to make both tests and application code as clear and understandable as possible. Her insights aim to align developers' understanding of their tests with the actual code, leading to a more enjoyable and productive development experience.

Better code through boring(er) tests
Betsy Haibel • Singapore • Talk

Date: June 22, 2017
Published: unknown
Announced: unknown

Speaker: Betsy Haibel

Event Page: http://www.reddotrubyconf.com/

Produced by Engineers.SG

Red Dot Ruby Conference 2017

00:00:04.110 good afternoon everyone thank you for having me here this afternoon we're going to be talking about testing a bit
00:00:11.080 I'm assuming for this talk that everyone in this room two things about everyone in this room first off that you love
00:00:18.939 testing at least in theory and second off that when it comes to your actual
00:00:24.580 test the ones you're actually dealing with on a day to day basis you maybe love those a little less everyone values
00:00:33.340 testing in the rails community now in the Ruby community we kind of won that battle and this is great even people who
00:00:40.090 maybe don't find as much value in test-driven development or in other specific testing practices still agree
00:00:46.600 that you need some kind of testing we find about testing even though we
00:00:52.600 collectively value it because pretty much no one loves testing all the time
00:00:58.379 even dyed-in-the-wool TDD fanatics like me it's okay to admit this the testing
00:01:06.310 police are not in fact coming for you today I'm going to help you fix that
00:01:13.630 mess today we are going to learn why we hate our tests and why we fight about them we're also going to learn about
00:01:20.140 some ways that we accidentally make our tests course by adding cancelling and making them a little too interesting all
00:01:27.400 is not lost though we are also going to learn about how to fix the ways we accidentally make our tests worse while
00:01:33.850 we're at it we'll learn about how we can make our application code better at the same time at the end of the day all I
00:01:39.909 want as a developer is boring code that I know that in four months I will understand in order to do this first
00:01:49.270 we're going to talk generally about some underlying causes of test pavéd and fights about testing then we're going to
00:01:56.110 cost through three specific ways that our tests can get annoying and learn how to fix their root causes so why do we
00:02:03.220 hate our tests the simple answer is that test our code and code is terrible and therefore tests are terrible but getting
00:02:12.040 a little bit less snark and a little more real we write our tests with imperfect knowledge we also write our
00:02:18.909 application code with imperfect knowledge we can make educated guesses about we'll meet in the future but that's all
00:02:25.830 they are is guesses we can never get away from our assumptions or from our current mental model when we write
00:02:32.250 application code and of course our tests run in the same group now whenever I've
00:02:38.160 made some incorrect assumptions in our code base and this has made our tests or application code or both really painful
00:02:45.690 to work with there's always going to use some guide and we'll td2 fanatics like me who insist on making a total jerk of
00:02:55.140 themselves they will say it is not a problem why don't you just try listening
00:03:00.750 to your tests and I of course know this because I have been the strict before
00:03:06.230 but why it is listening to your tab I've just listened to your test such a jerky
00:03:11.400 and annoying thing to say you're presenting your listener with this you
00:03:18.480 are giving someone this useless hole written math and then you are telling them they're stupid if they do not
00:03:24.420 magically understand what the question marks are and like I used to do this and
00:03:30.120 so I know to where people who say just try listening to your test means say is
00:03:35.130 I see something wrong and I kind of know how to fix it I think please just give
00:03:40.950 me a chance and so in this talk I want to fill in
00:03:46.590 the question marks a bit I want to fill these in but no one here has to feel stupid or sound like a jerk again before
00:03:55.860 I get started everyone takes deep breath bad code happens and bad test happens this is fine totally fine code is
00:04:07.049 terrible because the world is complex and well it's good to be honest with ourselves about when complexity is
00:04:13.080 useful or necessary complexity happens we are paid a lot of money because
00:04:19.430 complexity happens complexity happening to you does not mean you are bad
00:04:25.200 developer or a bad human it just means that this is a hard job also sometimes
00:04:31.530 you actually need an esoteric testing techniques none of these techniques that are thought to talk about as the test smells
00:04:37.780 are inherently bad they just can be overused finally I have done every
00:04:45.130 single thing I was out to show you in production especially the parts I say
00:04:50.170 are bad every talk I give is me lecturing my past self about a mistake I have learned better from and this talk
00:04:56.380 is no exception so if that out of the way let's begin the first test smell we are going to
00:05:03.040 look at today is testing private methods when you see this line of code in the test chances are someone is using it to
00:05:10.990 test a private method now I've heard a lot of different justifications for
00:05:16.960 testing private methods directly instead it indirectly through public methods they boil down to three things first
00:05:23.560 method might have weird indirect results that were hard to introspect otherwise
00:05:29.080 maybe the public methods were you used to test it we're really expensive maybe you've instead also wanted to
00:05:36.040 isolate this process from side effects these reasons are valid reasons that are hard to argue with even if you're
00:05:43.210 feeling uncomfortable about testing a private method so I suggest that we not try to confront these arguments and
00:05:49.030 instead sidestep them instead you can just make the method public which is
00:05:55.030 jokey but underrated if you're feeling a need to hit something directly and test it's probably important it might be
00:06:01.990 important that you need to hidden your application code someday maybe from admin interface or something you can
00:06:08.170 also use this as an opportunity to build more introspection logics if it's hard to check on whether a process completed
00:06:13.690 in tests then when you're debugging later on it's also going to hard to check on that done to your future self
00:06:20.140 at favor finally you can also extract a simple class there's a quick and dirty
00:06:25.900 way to do this to use a shim this is kind of like which opt out earlier in the functional programming talk where
00:06:32.350 you create a simple class and the difference is you're not different so
00:06:38.020 thing you're doing here is literally just copying and pasting the code from the old method into the new class and
00:06:44.100 refactoring down roots at your leisure this is quick this is Chi and there's nothing wrong with that
00:06:50.219 maybe there are other private methods you need to pull in in which they expect actually super awesome because you're
00:06:55.299 figuring out a new domain concept this gem technique might get you someplace useful quickly it might not if it
00:07:01.119 doesn't maybe you pull on the thread and gone the tangle and it's not productive
00:07:06.369 to fix that tangle right now if you can't get someplace with this technique quickly it's okay to fix it later
00:07:14.229 it's okay to fix it later it's more than okay it's better because we think you are learning when you go oh this is
00:07:21.129 harder than I thought is that you don't know enough yet in the meantime it's fine to practice harm reduction it's
00:07:28.239 fine to leave the code deliberately ugly in tests and in your application code as
00:07:37.089 well because that's the signal of the future that there's something wrong here maybe leave a to-do comment that way
00:07:45.339 when you do know more you can come back and fix it later the next smell we're
00:07:51.759 going to covering this afternoon is duplicate test so for this one imagine
00:07:57.519 if you will that we're running a donation service that works with nonprofits and our clients nonprofits we
00:08:04.419 serve each had a primary contact phone we can look up whether the phones are mobile or not and here's some tests that
00:08:09.969 do that we set the clients phone number
00:08:16.209 to a predetermined phone that we know is mobile and then check the result of that mobile phone method then we know do the
00:08:21.909 same for none landline phone I'm using mini tests here in these code samples at least common denominator but I want to
00:08:28.779 reassure you all that everything I'm saying this shock applies to our spec to the syntax of these two tests is
00:08:34.029 different but the semantics are the same there's very little meaningful
00:08:39.099 difference in how we write tests between death tests mobile phones and it can
00:08:44.649 have a mobile phone do both are bound in test cases where we set a client phone number and then verify that a method
00:08:51.069 returns the thing we expect anyway so you've got these clients you need to know whether they're using a mobile
00:08:56.860 phone our landline phone and unsurprisingly you also need to know this about your donors who also have
00:09:03.089 phone numbers so we test this the same way and now we've got some test duplication I don't know about you but
00:09:10.949 anytime I see code duplication in app code or in tests it makes my brain feel a little weird it makes me go there's
00:09:17.249 something here what do I do with it so how do we deal with this now there's a
00:09:23.699 wrong way that's very tempting first which is shared example groups there's a special DSL for these and r-spec in mini
00:09:30.449 tests we just share code between the two test classes like in our application code name you look you module so you can
00:09:36.629 fling all the shared code into module and then include that module in our test classes well this is a valid testing
00:09:43.740 technique in some circumstances I am client as a mistake here because it should almost never be your first no -
00:09:49.499 when you see test application when you look at the application code or test we
00:09:54.600 can see why our test as is very common are basically just a one-to-one mirror
00:10:01.860 of our application code and that means that our tests are making the exact same assumptions that our application code is
00:10:08.250 making over time that will lock us into these assumptions when we go to refactor
00:10:13.620 the code later we'll be changing the application code but not the test or maybe we'll be frustrated by future
00:10:18.779 requests that can flick with test assumptions and therefore require us to change a lot of test code as well as add new application code we could also try
00:10:27.120 reducing duplication by testing the module directly here you create a fake mini class and include the module in it
00:10:33.480 and then run your module test against that eighth class and again this is a great technique when you actually watch
00:10:39.360 to have a module but it ties you to the assumption that the code needs to go
00:10:44.699 into a module and that assumptions might not hold true if we turn the module into
00:10:51.179 a class instead and test that class directly we reduce duplication in much the same way that we reduced it when we
00:10:57.389 extract as a shared example group the test of module directly but in addition
00:11:02.790 to reduce the net duplication we're also improving our application code at the same time by listening to the offered
00:11:09.629 duplication our tests you're able to see it cluster of shared functionality and improve our application code by properly
00:11:15.570 encapsulating the single responsibility of phone number lookup this is a much more sustainable solution in the way is
00:11:20.790 a shared example group double down on the module architecture and locked us into it long term I'm out of this
00:11:26.670 example after a lot of times I've seen API clients in charge of modules but I can apply anytime you've got a module
00:11:33.030 that really wants to grow up into a real class the last test smell I'm going to
00:11:41.700 cover this afternoon is inventing the universe there's a particular kind of test where to paraphrase Carl Sagan
00:11:48.480 we're trying to bake an apple pie seriously from scratch and so you need to invent universe first you need to
00:11:54.450 plants and trees you need to water them pick the apples and harvest the flower and and and and finally you can test the
00:12:02.670 pie came out tasty the first stupid thing we can do when faced with an
00:12:07.770 obviously ugly test like this it's to do something about the issue set up it right away this hurts our job as developers is
00:12:15.240 organizing complexity and so we see when we see complexity that is not organized it sets up this itch at the back of our
00:12:21.720 skull but boring tests make boring code if you made any new test abstractions
00:12:27.240 now we'd be doomed the same mirroring nonsense we just learned how to refactor away from this is because we only have a
00:12:34.140 little bit of domain knowledge so far we know 12 lines of code about your name we
00:12:41.610 understand one possible path for creating one kind of tie and we know that one possible path is required for
00:12:47.400 application we do not know anything else anything we did to abstract this first
00:12:52.920 there would be total guesswork be using our current understanding of and assumptions about the problem come in to
00:12:58.500 guess it's abstractions you know what we've also been using our current
00:13:04.770 knowledge and our current assumptions to create abstractions yeah that's right our application code when you try to
00:13:10.350 make new test abstractions in advance of test duplication you risk making parallel abstractions to your
00:13:16.230 application code just like we saw in the module extraction example once
00:13:23.150 multiple test cases we actually have enough information that we can start to tell where our abstractions are once
00:13:29.570 we've got multiple test cases we can actually start thinking about tests about techniques we can use to encode
00:13:34.880 those abstractions now just like in the
00:13:42.050 last section I'm going to show you two ways I've seen people make mistakes by trying to encapsulate abstractions
00:13:47.420 within tests only code then I'm going to show you an application code only approach that I recommend is an alternative not also that in this
00:13:55.040 section things start to get a little less clear-cut the test approach is I'm going to show you while they can bite
00:14:01.010 you if you use an improv inappropriately they do have a lot of student leaders minute uses the first test approach I'm
00:14:08.900 going to tell you about is shared context our spec of the DSL for this again but in many tests what you need to
00:14:15.440 do is write a method and included your setup block and what our spec does is metaphorically equivalent to this maybe
00:14:23.480 you can even include the setup method in the module shared between test classes what you're going with the shared
00:14:28.820 context can also it can often be pretty benign methodically reinventing the universe from scratch every time you
00:14:35.150 write a test is painful and often times it is not a useful pain for example if
00:14:42.380 your application is a database it is okay to extract database cleaning logic to a shared context or our health or
00:14:47.390 file there isn't much of anything you can or should do in your application code about something that's test
00:14:52.760 specific in production it is kind of
00:14:59.240 unlikely that ordinary day-to-day procedures would require you to drop or otherwise clean a database maybe you're
00:15:06.320 doing some scary CI things or a baby you're just doing something scary I don't know but like bog-standard applications I don't usually drop my
00:15:14.150 database so this is an easy case of telling something it's test specific
00:15:19.280 from something that isn't but sometimes the things are going to a little less clear-cut we've stripped out all of the
00:15:26.480 in essential lines the test all the things that don't matter in our production code and we still have an
00:15:31.760 extended test setup it's fine that an object has a lot of dependencies it is always wise to
00:15:37.820 examine whether these dependencies are necessary but sometimes they are so the
00:15:43.520 conversations shouldn't stop there a pie without a filling is pretty sad and so
00:15:49.790 while I'm going to plaid a shared context here as a warning sign I don't want to talk down jail here by implying
00:15:55.880 the domain complexities of your production apps are the product of unnecessary or easy to remove
00:16:01.400 dependencies my experience is that that is never the case luckily though the
00:16:08.000 mitigations for necessary domain set up complexities and for unnecessary
00:16:13.690 complexities you don't quite know how to remove yet are pretty similar we'll get them in a bit but first I want to cover
00:16:20.930 one more false trail I should emphasize first but this is not a rant against
00:16:28.070 factory girl I used in many projects it is a great DSL for describing tests and
00:16:34.310 feed data when used effectively it just has a few traps factory girl enables and
00:16:41.390 encourages us to make factories dedicated test setup helpers such as line factory girl create pie makes a pie
00:16:49.220 of the filling and the line factory girl that create filling creates a filling
00:16:54.230 with a pie I could say with like shared context the problem here is hidden
00:17:00.800 dependencies that we are hiding the dependency of supplies have on fillings but in both cases if I stopped there we
00:17:09.170 would go back to the magic and particularly arrogant elves definition of listening to your tests the real
00:17:15.950 problem is never that something hides dependencies dependencies means code I
00:17:23.360 am NOT looking at right now 95% of the time that is on purpose I want to be
00:17:31.460 able to look at my dependencies when they misbehave but the rest of the time I put some of those other files I didn't need to think about them right now and I
00:17:37.790 want them to stay there and I want to stay not thinking about
00:17:42.920 the public tests that hide dependencies comes in when the dependencies that
00:17:48.560 they're hiding is the domain logic as a maintenance developer I love to know we
00:17:53.780 make ceilings in the course of making pies that's actually very important information for me to have so I'd like
00:18:00.590 to suggest that when your test cells get complex you start thinking about how to move the important things that your test
00:18:06.410 setups tell you about your domain into your application now there are a few
00:18:13.880 different ways to do this you can pull more of the set-up logic into the constructor for example you can also
00:18:20.330 make factory methods on class maybe these are a shorthand for invoking the constructor with certain configuration
00:18:28.150 you can even go full Java and build out honest-to-god Factory classes there is
00:18:34.220 nothing wrong with going full Java if your application needs that we usually
00:18:41.420 hide this logic and factory gorilla trails developers but when we decide to dig it out instead what we are doing is
00:18:47.540 saying that this piece of business logic is too important to delegate to our framework it's like when we're startup
00:18:54.830 we maybe want to get an agency to build a prototype but then later you want to say thanks you need to bring development
00:19:01.430 in-house getting core business logic under your own control rather than the controls of your framework is important
00:19:08.060 in itself even if your factories state test only if all our factory objects do
00:19:13.490 is make logic flow clear to developers and they are pulling their own weight
00:19:19.390 let's look at some more foreign actors make this more concrete this entire invent the universe test looks before we
00:19:25.580 started extracting some of its logic into factory methods and here's where we can get to by using application code
00:19:32.870 factories judiciously note just how much
00:19:38.090 code we were able to move into the application we're later developers can discover and understand it better and
00:19:45.460 because we've lost enough lines to actually fit this on our screen in a way that isn't a scare tactic let's victory
00:19:51.890 laugh I'm going to bump the font size scroll down net right we've got them
00:19:57.840 through everything we wanted to cover not quite yet and incidentally we're not actually just
00:20:05.910 doing this last bit because it let me make a DC flag but I could not resist this pretty moment of compound pride here so it's just the funny magic tricks
00:20:14.640 by insisting that our test be as boring as humanly possible we have isolated the
00:20:20.280 main concepts that we can use to also make our application code more readable by insisting on boring test code we make
00:20:26.970 our application code more boring but now we come to the trick part of magic
00:20:32.610 tricks this is a totally subjective this
00:20:39.360 is a whole series of subjective value judgments the problem lies in how we
00:20:46.620 define boring valuing boring code of a clever code is a really popular idea and
00:20:51.630 since we can all nod along to that popular idea we sometimes miss that it's a value judgment but if we don't define
00:20:58.920 boring code very specifically all we are doing when we say clever code is bad code is creating another way to call
00:21:05.730 code bad in order to convince you that I'm on the side of boring code this
00:21:10.920 whole talk I've been deliberately sticking on controversial territory everyone likes removing duplications but
00:21:18.180 when I talk about what I consider boring it's actually pretty hard to fail map safe ground when I say that factory
00:21:25.980 girls create pie is the literal opposite of boring it's a single line that should strike fear into the hearts of any
00:21:31.800 developer new to a code base and most developers old to it what I'm reacting to is a history of seeing that one line
00:21:37.560 imply thousands of lines of code but I suddenly need to care about but have no
00:21:43.290 easy way of searching for but the developers wrote out long they don't
00:21:49.140 think so maybe they've worked on the same code base for six or seven years maybe that developer has a good
00:21:55.920 intuitive feel for the thousands of lines and puts it domain knowledge and that it is that one line a factory girl
00:22:01.550 they don't need pointers how to refresh their memory on specific and so they might say the Java factory
00:22:07.420 version I'm recommending as useless verbosity for the sake of verbosity and this brings us to one of the central
00:22:16.960 questions that defines our day to day of software developers this right here is
00:22:22.660 the hard part it's the hard part because the answer changes people come up here
00:22:28.540 on these stages they give keynotes and they say here I promise you can solve all your problems with this new kind of
00:22:35.380 new object I am giving you or maybe they say you can solve all your problems by throwing patterns away and
00:22:40.690 embracing in tightly coupled monoliths whatever the technical solution is changing these talks but the attitude
00:22:47.710 there is one true solution somehow never does I could stop by saying that this
00:22:54.040 attitude turns us all into that jerk who asked to lie on you just whatever uses new kind of view object but that would
00:23:01.210 be lying because what's underneath that self-righteousness is the unchangeable fear of how hard this all is boring is
00:23:12.340 subjective because boring depends on the background of a team and the flight cycle stage the product is in brain is
00:23:20.470 subjective and boring is hard to get right and we are afraid of not getting it right and we are afraid of what right
00:23:27.340 is changing on us so that even if we get it right now it suddenly becomes wrong
00:23:32.620 six months down the line but if code
00:23:38.590 doesn't stay right doesn't that just mean our product has grown I think
00:23:43.990 that's something to celebrate to me the magic of test rooms vine of
00:23:49.600 learning to hear what your tests are saying is that gives us a way to figure out what the correct code is for right
00:23:55.600 now it gives us a pass through not just everyday simple decisions like should I
00:24:00.880 make this method private but also party decisions that people might disagree on more loudly to talk about these hard
00:24:07.120 decisions I need to talk about some controversial things that's right I'm going to talk about mocks it gets worse
00:24:16.060 I'm also going to need to talk about controller tests I am even are you ready
00:24:22.170 going let's you need to talk about my first services now when I think about
00:24:31.690 boring code this rails controller method here is basically my Platonic ideal I
00:24:36.930 want to update a blog post so I find the post in the database try to update it and render a response
00:24:42.250 it reflects whether the updates succeeded or not there be a few changes to method names some security
00:24:47.410 improvements etcetera in the past two rails fusions but for me of nearly a decade ago who is firming rails 2.3.5
00:24:54.370 would look at this method and not find anything weird to me that's boring as hell and yet controller tests are very
00:25:02.320 hard and as a community we have a lot of opinions about them here's a pretty
00:25:07.780 standard taffy path test for this controller method even this simple controller method the happy path test we
00:25:14.410 need to do some complicated stuff before
00:25:20.110 the test even runs there's an invisible set up phase against database transactions we can get clean the database quickly later we then create a
00:25:27.400 post using active record which takes only one line but can potentially invoke a lot of other code then we indirectly
00:25:33.700 invoke the controller method by using rat tests to trigger the full action dispatch stack finally we test both
00:25:39.610 response and also for side effects whether the post body has been updated or not this is a lot of stuff this a lot
00:25:46.570 of stuff can take a lot of time to run and so in the rails community for a while there was a fashion for cutting
00:25:52.990 out a lot of this time with test bevels a full discussion of test doubles is outside the scope of this talk and
00:25:59.140 that's a really fun thing to say but briefly for those who aren't familiar mocks are completely fake objects so if
00:26:06.880 we needed a post someplace but didn't want to go to the trouble of building one out using active record we can
00:26:12.550 create a mock post but just return to test for the post body we can also create partial mocks by taking existing
00:26:19.360 objects and altering them so the method always returns with subs value finally we can have either a full or partial not
00:26:26.050 expect that a message will be received this means that unless meth is called
00:26:31.670 during the course of that test the test will fail now here's the controller
00:26:41.120 tests written during that bad usually look like looking at this you can kind of see why it fell out of style this
00:26:47.420 test is much longer kind of ugly and it's super brittle if you change
00:26:52.580 anything about the way that finders are being invoked in the controller all of sudden everything will shatter into red
00:26:58.120 it'll shatter and red even if the code will actually does the thing you want to do and so a lot of sites that controller
00:27:06.080 tests that I've seen are receiving people who look at this and ask but why would you even do that and people look
00:27:11.210 at say this and say okay this is ugly but our mocks are clearly telling us something about the design of the
00:27:16.280 underlying application code if you're doing test-driven design you might
00:27:21.860 instead write a test looks like this begin with the interface you want to see in the world just one line of mocking so
00:27:28.970 nice so simple so pretty and yet when we look at the application code that it
00:27:34.610 implies how many of you actually do is in the real world how many of you are
00:27:39.620 have luck convincing your co-workers to do this in the real world the code
00:27:44.660 doesn't quite seem boring anymore it's not very Braille Z and these are hand
00:27:49.790 wavy ways of talking about something that's very real we have made the
00:27:55.670 project less discoverable we have made the project less accessible newer developers when I say newer developers
00:28:01.520 please remember I am NOT talking about juniors I'm talking about people new order of projects unit developers are entirely capable of comprehending these
00:28:07.460 patterns non-standard practice have their place but discover and
00:28:13.730 accessibility are real values - we condescend to people who don't like non-standard patterns by implying that
00:28:20.030 if they don't like them they just need to learn to code better we are retiring the rhetorical trick we are erasing the
00:28:26.720 very real and very valid values michmash what's going on by telling ourselves
00:28:32.390 it's a skills mismatch instead and that since we're smarter we must be right
00:28:38.140 that is in the real world is okay to ignore most of the bear complexity on a controller test a lot of
00:28:44.450 projects have gone back to this style of controller testing they're fine it's predictable it's easy to read we think
00:28:51.440 nor the complexity buried in this test because it's framework complexity that we can trust will stay buried lotuses
00:29:00.140 become an issues sure but if slowness becomes an issue then maybe the answer
00:29:05.870 isn't doing complex things in the test its deleting the test if a test isn't
00:29:11.600 providing you with a lot of values then why should it be there so I've just down
00:29:19.429 here is traveled up and then back down and then back up the realism continuum when you're dealing with test complexity
00:29:26.210 one of the things you're always doing is trading off a feel is Tritton off a feeling of realism against the ability
00:29:31.730 to focus on exactly one thing at a time and when I say the feeling of realism that's very important because realism is
00:29:38.929 not the goal here even if it feels like a nice security blanket when we exercise
00:29:44.330 a lot of lines of test of code realism is a proxy for the ability to change the
00:29:50.870 boundaries of our code arbitrarily in case we've gotten our assumptions wrong and so in this world a test book
00:29:57.620 dynamically persisted objects exercises everything is risky because it tests a
00:30:03.740 lot of things accidentally we aren't the thing you're necessarily looking at but also lets us arbitrarily change the
00:30:09.830 object structure around a test that uses test doubles extensively on the other hand it's going to be working with a lot
00:30:16.160 of assumptions that might be wrong but it's going to test a much smaller set of things and be more targeted what's
00:30:25.880 interesting about this is that we be faced with pretty much the same set of concerns its instead of looking at the
00:30:31.250 database directly we're retrieving posts and comments from some kind of blogging engine microservice or decide look like
00:30:40.580 in this case how do we change this controller maybe it looks like this
00:30:48.070 more the point how would change our test here's our test again using this very
00:30:55.970 realistic boundary ability to change preserving style and active record so if
00:31:07.190 we're going to maintain spirit of full realism we want to create things on the external service directly right full
00:31:13.730 end-to-end test totally okay any change the test itself with this be very simple very easy to write and yet no one does
00:31:20.780 this and no one does this because in those cases everything surrounding the
00:31:26.150 test is totally horrible connectivity issues are the thing that everyone
00:31:31.940 brings up here but even worse than connectivity issues is the fact that all the sudden we tirpat all of this test
00:31:38.660 test setup and teardown ourselves real stuff a lot of work for us when we're dealing with the databases the external
00:31:44.990 service were dealing with to handle that setup and teardown and it's very easy to
00:31:50.870 lean on that invisible 10 years of work by open source prompt people I don't
00:31:59.510 know about you but when I move into microservice libya where there's a little less support code I don't want to
00:32:06.200 suddenly take on the burden of that ten years and become like personally responsible for writing a duplicate and
00:32:13.940 sorriness world mocks start to look very attractive to me you basically can't operate without them okay so we're still
00:32:22.640 in denial about that and so one thing we can do instead of going for a fully mock test is to preserve some of the quote
00:32:30.740 unquote realism by which we actually mean the flexibility to change boundaries within the code later that in
00:32:37.550 full end-to-end test could give us by using the web mock library web knock allows you to set mock responses to HTV
00:32:45.500 requests made to any given URL this greatly reduces test setup and test
00:32:53.360 hair down I have two relatively resilient against change but I personally find when I use this method
00:33:00.200 for external service testing I find myself needing to care a lot about service details that aren't necessarily
00:33:07.100 relevant to the test I'm writing and that itself is a test awkwardness but I
00:33:12.140 feel the desire to listen to in that spirit let's go back to full mocking as
00:33:19.040 a valid technique let's look at how this test this test right here that is a copy of one we saw earlier as the fully
00:33:25.910 mocked repository test how the test might evolved if we use mocks heavily in
00:33:31.850 a micro service world hey there's barely any change the
00:33:43.130 interesting thing about this is that if we followed the heavy mock style of testing all along we would have been
00:33:48.830 prodded towards the repository pattern for our posts early on that would have helped to guide our decision to extract
00:33:54.890 a blog surface when we needed to there would have been this big repository clash somewhere shouting extract me and
00:34:01.430 it would have been so easy whether you like mocks or not I think
00:34:08.210 that the objects you extract when you listen the complex controller tube setup are a pretty fascinating guide to the
00:34:15.080 actual overall shape of your application whether your team monolith or team micro
00:34:20.210 service or team I don't care - so code work having that level of structure
00:34:25.850 helps manage the necessary complexity is that all older and larger code bases accumulate listening to your tests isn't
00:34:32.540 the only way to arrive that architecture but since these are hard problems I think we can all use as many tools as we
00:34:38.390 can get regardless of what boring application code looks like to you
00:34:43.970 or boring test code the thing I want you to take away from this talk is that whenever you are writing tests you are
00:34:50.540 writing them about your current understanding of your code duplication is cheaper than the roam abstraction
00:34:56.090 applies to test code too when you do introduce test abstractions they are likely
00:35:01.119 mirror the assumptions you are making your application code because humans are fascinatingly self-deceptive creatures
00:35:08.940 application code influences test code and test code influences application code and so what ever boring does mean
00:35:16.240 to you sometimes the easiest way to make our tests more boring to hate our tests
00:35:21.430 less is to just make them more boring we do in fact have that power we can then
00:35:30.279 trust that our application code will fall into line that's all that listening
00:35:36.670 to your tests means it means the points of where you hate your tests are opportunities to refactor so that you
00:35:42.880 hate both your tests and your application code left so I'm Betsy cable
00:35:49.180 I go by Betsy muffin on the quitters but if you follow me you will get a lot more
00:35:54.730 cat photos and US politics and Tech Talk and you can also find me on the internet
00:36:02.170 at Betsy hable calm and github comms flash be table do you have time for
00:36:16.780 yes we do have time for questions does anyone would ever like to volunteer
00:36:24.200 question hey so you showed this example
00:36:34.940 where you moved ah where you introduced the repository and then in the controller test you just stopped about
00:36:41.870 the discipline story now then you need to test for the repository itself right and what would you do there would you
00:36:49.730 use mocks or would you just use the direct connection to the database and if if use mocks in that case then what is
00:36:57.200 the real advantage you're just moving the marks from the controller test to the repository test you're introducing
00:37:03.680 additional concept and then then you just put it into the files but what's the real advantage there
00:37:09.470 well that's Australian because I would just use active record methods there
00:37:16.390 when you tie yourself to any one specific method and say this is the correct method of all time you lose the
00:37:22.730 ability to make trade-offs and whether to use mocks or not is incredibly
00:37:27.890 situational if I were to use mocks in a repository test or a query object test
00:37:32.990 or any test where what I'm doing is testing how these very specific queries
00:37:38.210 that I'm using active record to write play out in the context of the database then I would be tying myself very hard
00:37:44.060 to my implementation and I never want to be doing that I would be losing the
00:37:50.030 ability to maybe optimise the query by hand rolling sequel later I'd be losing the ability or to do that easily rather
00:37:56.300 I would be not really testing anything I whenever you see a very long long
00:38:03.650 sequence of mocks that all view with the same object the chances that your test is doing something that's worth doing
00:38:10.340 gets very low and sometimes the feedback you need is tricky factor but sometimes
00:38:17.780 the feedback you can take from that is that this test you need a different strategy for our perhaps don't need
00:38:29.020 thank you for the talk I agreed with basically everything except for the last
00:38:35.000 and one of the last slides where you do the mocking or I don't know stuffing at and I still don't know the difference
00:38:40.910 when you run the post test against the controller and you test if the service
00:38:46.940 object receives a post underscore update like if the method is called and I
00:38:52.520 didn't understand why you do that why don't you just test and why don't you just run the controller and then test if
00:38:59.440 the like I mean you still have to find out the ID of the updated post but you
00:39:05.630 why don't you just test if that really got updated with all the knowledge about the service object well it's very nice
00:39:11.840 that you was mostly agreed with me that's very validating and I needed that I'm sorry I'm being are you being
00:39:17.900 sarcastic I'm totally being sarcastic
00:39:22.930 but to answer the part of that that was actually questioned I think what that
00:39:30.680 demonstrates is the fundamental futility of a lot of controller tests I think
00:39:36.350 that when a test basically tests whether
00:39:42.830 a method is being called or not then oh no I can do that by looking at the code
00:39:50.150 I can do that by running a more end-to-end cast higher up attacking the
00:39:56.420 testing pyramid there's a dozens of ways to test that controller tests have their place but controller tests have their
00:40:02.300 place when the thing you're testing is more complex stuff like whether your authorizations are working correctly
00:40:08.990 and in those cases okay so you you say
00:40:14.840 you test if the service object gets run in the controller test and you test the
00:40:19.970 service object itself in a separate test yes okay so but then ok so then
00:40:26.060 basically I would basically asked the same question like how do you test the service object okay okay thank you
00:40:36.320 good ok so just now look at the
00:40:45.990 controller test you made I think the like very elegant solution are very shot
00:40:51.500 it actually removes a redundancy in the current controller testing but also
00:40:58.050 fields or installation the more robust version kind of feel like integration
00:41:04.680 testing so I was feeling that you are making computer test controller test a unit test instead of an integration test
00:41:12.110 so we're just wondering what's your opinion on the integration testing which is kind of miss out I think they're
00:41:21.180 trying to divide clean lines between unit test integration test it's almost
00:41:27.420 always mistake or not almost always I think that you want to have some higher
00:41:36.240 level tests that exercise more of the staff and to follow the testing pyramid but I think that as you get lower and
00:41:43.200 lower level you don't necessarily want very fine-grained unit test coverage of
00:41:48.600 everything because some of your units mostly exist is coordinating units and again I think that you're not
00:41:53.820 necessarily getting much value a lot of the time from testing that that coordination happens it isn't also being
00:41:59.250 captured by tests or higher in the stack and so I think that when you make a lot
00:42:05.730 of to do about is this a proper unit test is this a proper mid level integration test etc then what you're
00:42:12.960 doing is forcing yourself into the current assumptions of your object
00:42:18.420 structure again in a way that makes that object structure much harder to change later when it's no longer serving you
00:42:24.300 and so I think that tests that are more integration aid even though a lot of
00:42:31.020 people think they're less technically correct from like a test peer ISM
00:42:37.290 standard I think that the reason they keep on emerging in real-world practice
00:42:43.530 is because underneath pragmatically people are drawn to the idea of
00:42:49.300 thing that they think is going to ease your change later and I think that's valid yeah yeah yeah I agree I think
00:42:58.120 that makes a point that you're saying integration testing is kind of unnecessary as if all your unit has
00:43:05.740 passed it should just work and you shouldn't just you should not need to test the coordination between different
00:43:12.040 units and also because you don't test the actual underlying integration is
00:43:18.340 easier to make changing your actual needed nitty-gritty of your coding it is that your take on the issue I'm sorry to
00:43:27.730 your pizza is like by removing removing the very DQ robot integration testing
00:43:36.270 but focusing our unit testing and assuming the unit's coordination is
00:43:43.690 correct is actually making the changes
00:43:49.330 easier in the future because without boil down to the actual BQ you can
00:43:56.920 change stuff without affecting your test yeah I mean ultimately a lot if you have too many full integration tests opponent
00:44:03.910 and then test you're doing a lot of duplicate work all the time and you're not necessarily getting much marginal
00:44:10.330 value from each individual test and even though you're not doing that as a human you're still making your CI run that and
00:44:17.790 the level to which a CI that takes an hour run versus levels yeah and effect
00:44:26.440 that LCI that takes five minutes to run is very different the level of effort or the level of attention that people pay
00:44:31.570 when CI starts to take four hours to run is virtually nil and you need to keep
00:44:37.690 that in mind but it's more than that it's that the past a certain point
00:44:44.580 trying to multiply end to end pass to the wolf game there's a really great
00:44:49.840 point I saw recently on Twitter that a game developer was making and this game developer had worked on a
00:44:55.430 game where you had to do a lot of combinatorial simulation and so she was
00:45:01.280 all okay we can't actually QA this game fully because QA in this game fully we
00:45:06.680 have 500 options for this x 500 other options for this well buy 500 options
00:45:14.180 buy 500 options and all of a sudden you're getting to a point where forget a
00:45:19.580 human tester not even a computer computer tester can meaningfully exercise all of that and that's fine
00:45:25.610 what you do is you look for this you look for a few simple cases of smoke tests and you look for the esoteric
00:45:33.530 cases they're likely to give you bugs and you pick and choose what's actually useful to run yeah great thanks cool I
00:45:43.010 think what time for one more question if there is any any more questions nope
Explore all talks recorded at Red Dot Ruby Conference 2017
+12