00:00:00.000
ready for takeoff
00:00:16.920
thank you for coming
00:00:19.560
my name is Caleb harth and while I
00:00:21.960
usually prefer to keep my introductions
00:00:23.820
brief at the beginning of talks and talk
00:00:25.619
employers and promotion and all that
00:00:27.300
stuff later
00:00:28.680
since you're already here and I don't
00:00:29.760
have to actually convince you to come uh
00:00:32.820
and we're probably all here for the same
00:00:34.860
reason
00:00:36.120
but in this case I do want to touch on
00:00:37.620
my background because it helps to
00:00:38.760
underline the point of my talk
00:00:41.100
I've worked in Ruby on Rails for about
00:00:42.899
10 years
00:00:43.980
and across that time I spent about five
00:00:45.600
years each of product product and
00:00:47.640
Consulting companies
00:00:49.620
I currently work at test double A
00:00:51.360
consultancy specializing in embedding
00:00:54.180
within software teams to help build
00:00:55.739
better software and better teams and
00:00:58.140
previously I worked at thoughtbot across
00:00:59.699
a variety of Greenfield and established
00:01:01.140
rail faps
00:01:02.520
you can find me on my blog online
00:01:05.220
where I write about various programming
00:01:06.780
Concepts like ethics best practices and
00:01:09.479
testing
00:01:10.920
and since the bird site is done now you
00:01:12.960
can find me on Mastodon
00:01:14.580
at dice dot camp at Caleb or just by
00:01:17.340
searching Kayla parth
00:01:20.159
throughout my career I've had the
00:01:21.299
opportunity to work in dozens of apps
00:01:23.880
each with their own test Suites and
00:01:25.320
strategies for testing and that's given
00:01:27.000
me a chance to compare a lot of
00:01:28.020
different ways of writing tests
00:01:30.479
one little let and a tiny bit of before
00:01:32.640
often seems like a good idea but I've
00:01:34.920
seen them grow organically into these
00:01:36.540
spider webs of complexity that are very
00:01:38.400
difficult for not only new members of a
00:01:40.439
team to grasp but for grizzled veterans
00:01:42.420
to reason about as well
00:01:45.259
let defines a memoized helper method
00:01:48.000
give it a name and a block to execute
00:01:49.979
and it'll execute that block zero or one
00:01:52.799
time depending on whether you call the
00:01:54.360
method store the result and return it
00:01:57.180
on subsequent calls it'll return that
00:01:58.799
stored result without executing the
00:02:00.360
block again
00:02:01.799
if you dig into the definition it's
00:02:03.240
almost exactly defined as a plain Ruby
00:02:05.280
method
00:02:08.759
a let method can be referenced by other
00:02:10.500
lets
00:02:14.099
and depending on the nesting in that
00:02:16.140
reference may be to a different method
00:02:17.640
definition in different specs
00:02:22.140
subject can also reference let methods
00:02:24.720
speaking of subject they're basically
00:02:26.400
just a let block with special semantics
00:02:27.900
since there are some methods like it is
00:02:29.940
expected to
00:02:31.140
they use the subject name implicitly
00:02:34.620
you can also give subjects other names
00:02:36.360
while maintaining those same semantics
00:02:40.020
but effectively subject is just a let
00:02:41.519
method named subject so every time I say
00:02:43.680
let I mean subject as well
00:02:47.459
before blockage executed before each
00:02:49.680
spec that it is in scope for which is to
00:02:51.540
say any describe or context block that
00:02:54.180
contains both the spec and the before
00:02:55.680
block regardless of how deeply nested
00:02:58.019
will execute the before block
00:03:01.319
now I'm going to use before here to
00:03:02.700
stand in for after as well because they
00:03:05.160
behave exactly the same just at
00:03:07.080
different times and the same thing for a
00:03:08.280
round
00:03:11.159
a before block can reference let
00:03:12.720
variables or any other methods that
00:03:14.519
would be in scope for a test including
00:03:16.200
subject or let methods
00:03:20.040
now I apologize hopefully you can see
00:03:21.780
some of this
00:03:24.000
I overestimated the contrast that a
00:03:26.340
projector and bright lights can handle
00:03:28.860
so let's take a look at an extreme but
00:03:30.659
real example of one reason that let and
00:03:32.640
subject are problematic
00:03:34.560
this is a 4500 line unit test for the
00:03:36.599
god object of an app I once worked on
00:03:39.720
before I started the project I began to
00:03:41.220
refactor it
00:03:42.360
it makes heavy use of let not just for
00:03:44.400
the main model but for many other
00:03:46.319
methods as well
00:03:54.120
drink that in
00:03:57.299
4 500 lines there are 531 let
00:04:00.180
definitions across 131 different method
00:04:03.000
names
00:04:04.260
78 of those are overridden in different
00:04:06.239
describing context blocks nine of those
00:04:08.700
are redefined at least 10 times
00:04:11.040
with a maximum number of redefinitions
00:04:13.500
of 69.
00:04:17.519
in addition to that there are 87 times
00:04:19.260
that subject is defined
00:04:20.820
and in almost every one of those cases
00:04:22.260
the type of the subject is different
00:04:23.580
from the original definition which is to
00:04:25.860
say that some method or attribute of the
00:04:27.540
system under test or a collaborator is
00:04:29.820
being referenced to subject and not the
00:04:31.320
system under test itself and that the
00:04:33.300
subject is returning a different type
00:04:35.220
of object in different specs
00:04:39.840
overall almost 14 of this file is
00:04:42.300
dedicated just to let and subject lines
00:04:43.919
not including multi-line blocks
00:04:46.800
where the values are actually being
00:04:48.000
defined
00:04:51.600
much of this structure is front loaded
00:04:53.100
in the spec in place to support an
00:04:55.080
extremely complex General fixture
00:04:58.740
General fixture is one of the root
00:05:00.060
causes for obscure tests which simply
00:05:02.220
means that it's a different it's
00:05:03.840
difficult to understand at a glance
00:05:06.000
General fixture is the term and obscure
00:05:08.400
test are terms that Gerard messeros uses
00:05:10.620
in X unit test patterns
00:05:12.720
to describe when a test builds a larger
00:05:14.520
fixture than is necessary to verify the
00:05:16.199
functionality in question
00:05:19.139
in Ruby and R spec terms
00:05:21.120
at the beginning you can see that white
00:05:23.100
block up at the beginning
00:05:24.840
there are 31 let definitions in place to
00:05:27.060
parameterize the default subject
00:05:28.560
instance this is all set up that's
00:05:30.479
needed that is not needed for most tests
00:05:33.300
but because one or two describe or it
00:05:35.280
blocks needed to reference some Behavior
00:05:36.900
All specs in this file now need to do
00:05:38.880
that work unless they Define their own
00:05:40.380
simpler subject
00:05:44.039
this is harder to visualize but the
00:05:45.660
majority of these methods are also
00:05:46.800
defined such that they're only used in a
00:05:48.660
single spec
00:05:49.680
they'd be so much simpler and clearer if
00:05:51.240
they were inlined into the IT block
00:05:53.880
needless to say it's quite difficult to
00:05:55.440
reason about given a given a let or
00:05:58.080
subject method
00:05:59.520
where what it contains and where to even
00:06:01.500
find it
00:06:02.520
it isn't uncommon in this file for a let
00:06:04.740
or subject to find hundreds of lines and
00:06:07.020
several block Scopes outside of where it
00:06:08.520
was being referenced when I was
00:06:09.660
refactoring
00:06:10.800
I had to jump 350 lines up
00:06:13.500
to find the correct let's
00:06:17.160
now I wanted to share all of this
00:06:18.479
because as we move into a more contrived
00:06:20.100
and more manageable example for the
00:06:21.419
amount of time we have to refactor we
00:06:23.699
should know that in the real world there
00:06:25.080
are test Suites that look like this and
00:06:27.000
in fact in my experience this is where
00:06:28.500
most specs that use the majority of our
00:06:30.479
spec Trend toward over time
00:06:33.000
our goal should be to have manageable
00:06:34.380
understandable and maintainable tests
00:06:36.120
that we enjoy adding to and making
00:06:37.740
changes in
00:06:45.080
so we have a situation where we're
00:06:47.100
defining a method which Latin subject
00:06:48.840
both are just with extra steps but it's
00:06:51.240
hard to track down because these macro
00:06:53.160
they're done through these macros and
00:06:55.080
they're intentionally easy to redefine
00:06:57.539
beyond the navigation issue these
00:06:59.699
methods construct themselves by
00:07:01.020
referencing other let variables and
00:07:03.120
across different specs those delegations
00:07:04.800
are being referenced are referencing
00:07:06.660
different methods
00:07:08.039
what I talked about with the different
00:07:09.300
contexts earlier
00:07:11.100
well the code seems to be doing the same
00:07:12.600
thing across different specs it's in
00:07:14.160
actuality running through completely
00:07:15.360
different code paths that are being used
00:07:16.620
and it's very difficult to track that
00:07:20.099
finally especially in the case of
00:07:21.599
subject it's common for the actual type
00:07:23.460
being returned to change between
00:07:24.539
different describer context blocks you
00:07:25.979
really have no idea what you're dealing
00:07:27.120
with when you call this method
00:07:30.300
so what are we what are our options for
00:07:32.940
refactoring out of this
00:07:34.860
perhaps the simplest option is to Simply
00:07:36.660
replace a let with an instance variable
00:07:38.400
for example let book could be ad book
00:07:42.419
well this technically checks the avoid
00:07:44.160
let box and may be slightly more
00:07:46.259
performant than a memoized lookup method
00:07:48.539
it maintains a lot of the same issues
00:07:50.639
specifically that they're likely to be
00:07:52.020
overridden or defined differently in
00:07:53.580
different contexts so there's little
00:07:55.139
chance of finding the correct definition
00:07:56.280
for a given text in a speck of even
00:07:58.560
moderate complexity
00:08:01.319
another option that solves part of the
00:08:03.419
problem is to change these let and
00:08:04.979
subject definitions to properly defined
00:08:06.360
Ruby methods
00:08:07.860
this involves memoization via instance
00:08:09.660
variable or equals some calculation of
00:08:11.520
the value
00:08:12.539
and doing this improves the odds that
00:08:14.039
automated introspection tools such as C
00:08:15.660
tags or language servers are able to
00:08:17.639
find the correct definition
00:08:19.560
the approach does not help with the
00:08:21.120
second part which is that these are
00:08:22.319
being redefined in different contexts so
00:08:24.720
depending on their nesting you're still
00:08:26.819
dealing with different methods
00:08:30.539
the third and the one that I recommend
00:08:31.979
here is the inline method refactor
00:08:34.680
this method uh was originally named by
00:08:37.200
Martin Fowler in refactoring improving
00:08:39.899
the design of the existing code
00:08:43.140
and it's pretty straightforward instead
00:08:44.520
of pulling these variables into a letter
00:08:46.020
subject Define them directly in the test
00:08:50.640
but Caleb I hear you saying this is
00:08:53.040
repeating yourself and we don't repeat
00:08:54.600
ourselves that wouldn't be dry
00:08:57.540
this is a point that's a common
00:08:58.560
simplification of don't repeat yourself
00:09:01.320
Andy Hunt and Dave Thomas and the
00:09:03.180
pragmatic programmers stated the dry
00:09:04.620
Principle as
00:09:06.060
every piece of knowledge must have a
00:09:07.800
single unambiguous authoritative
00:09:10.320
representation within the system
00:09:12.360
one of these words matters here
00:09:13.740
knowledge
00:09:15.660
the goal of dry is to avoid duplication
00:09:17.339
of knowledge and not duplication of code
00:09:20.040
now it turns out the duplication of
00:09:21.600
knowledge also tends to reduce code
00:09:23.100
repetition
00:09:24.660
but that's a side effect and not the
00:09:26.040
primary purpose of dry
00:09:27.779
it's often simplified to new programmers
00:09:29.399
myself included that they are learning
00:09:32.100
about dry as deduplicating code
00:09:34.620
even though it helps with do and even
00:09:36.660
though this helps with
00:09:37.880
deduplication of knowledge it leads to
00:09:40.560
premature extractions of code that need
00:09:42.839
to be then parameterized to support
00:09:44.279
different use cases
00:09:47.040
the default version of subject which is
00:09:48.839
defined as described class.new or Mark
00:09:51.660
concretely in our example book.new
00:09:54.300
is really more of an indirection than a
00:09:55.860
consolidation of knowledge
00:09:57.480
book.new is already a method writing it
00:10:00.240
into a subject doesn't dry anything out
00:10:01.980
but even if it did in the case of tests
00:10:04.560
I'd argue that knowledge duplicate
00:10:06.060
deduplication is not necessarily a good
00:10:07.860
goal
00:10:08.940
I've called these test specs because
00:10:10.440
colloquially that's generally how I've
00:10:12.240
heard them referenced but our spec
00:10:14.100
actually defines them as examples and
00:10:15.839
I'm glad that it does because it points
00:10:17.279
that the code that you're writing should
00:10:19.080
look like how it is used
00:10:22.320
David Bryant Copeland recently wrote Our
00:10:24.839
spec examples are well examples
00:10:27.720
the article's thesis is that avoiding
00:10:29.880
predicate matters such as expect order
00:10:32.040
not to be sent should be avoided in
00:10:34.560
favor of expect order sent to equal
00:10:37.920
false which is a good point
00:10:40.260
I have to say it's a good point because
00:10:41.519
unlike Gerard messero smartenfeller or
00:10:43.380
to a lesser extent Dave Thomas
00:10:45.360
David might actually be in this room or
00:10:47.459
at least at the conference
00:10:51.720
but taking David's Point even further
00:10:53.339
it's desirable for each example to be a
00:10:54.899
self-contained example of how to
00:10:56.399
reproduce Behavior
00:10:58.920
our spec example
00:11:01.440
real world example following that
00:11:03.660
pattern given any individual R spec
00:11:06.120
example in isolation we have all the
00:11:08.579
knowledge to reproduce the behavior
00:11:09.899
specified in the example in the code
00:11:12.600
base itself or in our own code if this
00:11:14.459
is the gem or some other shared code
00:11:19.079
drying tests imagine that I had a nice
00:11:21.180
visual here of like taking code from a
00:11:23.160
spec file and into but I didn't have
00:11:25.680
time
00:11:27.480
drying test reduces the utility of each
00:11:29.279
example by relying on shared utility
00:11:31.140
methods or Worse unshared utility
00:11:33.180
methods that convolute what's actually
00:11:34.500
happening in the tests if you can't look
00:11:36.480
at an example and understand what's
00:11:37.800
being tested how the system under test
00:11:39.839
is intended to be used and to be
00:11:41.640
confident that it actually works
00:11:43.560
then your example is not really living
00:11:45.060
up to its full potential as living
00:11:46.800
documentation
00:11:48.959
so my advice for test setup is to write
00:11:51.420
everything twice
00:11:53.279
or hopefully more than twice
00:11:55.980
Embrace that there may be a bunch of
00:11:57.600
setup that's duplicated between examples
00:11:59.940
because these examples are documentation
00:12:02.399
doing the setup inline allows you to
00:12:04.440
write only what you need in the test
00:12:06.720
and not to build out fixtures that
00:12:08.040
support multiple things
00:12:09.720
it also shows the difficulty of using
00:12:11.579
your code to Surface by surfacing the
00:12:13.800
collaborators
00:12:15.060
the arguments the class another setup
00:12:16.980
that's required to be in this
00:12:18.600
environment before you can even run the
00:12:19.920
code
00:12:22.200
complexity introduced in the name of
00:12:24.420
decreased repetition of the code does
00:12:26.579
not make your specs better and it's not
00:12:28.560
a worthwhile trade-off just to hide test
00:12:30.959
setup
00:12:33.600
if something's difficult to test that's
00:12:35.339
a smell that you're either testing the
00:12:36.600
wrong thing for example you might be
00:12:38.459
testing the return value of another unit
00:12:40.140
test of another unit tested method in
00:12:42.839
another class in that case you can
00:12:44.639
safely mock out the collaborator and
00:12:47.519
just pass the return type that you need
00:12:49.200
because you can be confident that the
00:12:50.820
other class is working correctly if it's
00:12:52.500
test pass then you can have a single
00:12:54.000
integration test that proves that they
00:12:55.320
work together
00:12:56.820
or it may be that your object has too
00:12:58.500
many collaborators and may be able to be
00:13:00.959
refactored to avoid a complicated setup
00:13:03.300
by reducing its fan in or a number of
00:13:05.339
collaborators that relies on
00:13:09.839
since Mastodon is the cool new place to
00:13:12.420
be and as a rails app I thought we could
00:13:14.279
take a look at a portion of its tests
00:13:16.260
for our refactory example here's the
00:13:18.420
full spec for the mute bang method split
00:13:21.120
into three columns to better fit on a
00:13:22.920
slide
00:13:25.079
this is a test of the mute functionality
00:13:26.940
of an account and if you'd like to
00:13:28.680
follow along later
00:13:30.120
uh it lives in Spec models concerns
00:13:32.940
account interactions spec.rv
00:13:37.680
I know that you can't read any of this
00:13:39.060
text
00:13:39.839
that's okay I'll be talking through it
00:13:41.700
as we go and use Bolding in color and
00:13:43.500
some animations to help draw attention
00:13:44.940
and help you understand what's happening
00:13:46.320
at the macro level even though line by
00:13:48.420
line you won't really have any idea
00:13:51.480
so we can see that the spec overrides
00:13:53.880
the default subject and that it's used
00:13:55.740
nine times here across about 100 lines
00:13:57.600
of code subject is a good place to start
00:13:59.519
when we're refactoring out of this
00:14:01.019
because it when it's used at all it's
00:14:03.899
used in almost every example
00:14:07.139
as I mentioned we can use the inline
00:14:08.760
method to take the body of the subject
00:14:10.500
definition and place it directly into
00:14:11.820
the body of each spec
00:14:13.260
thanks to scoping even though the
00:14:14.820
subject definition referenced account
00:14:16.560
Target and ARG notifications
00:14:19.079
all of which are let methods the code
00:14:20.639
will continue to run here and have
00:14:21.839
access to those methods
00:14:24.540
one thing to take a look at is that
00:14:26.700
these tests have a very similar and
00:14:28.440
non-flat structure which and can be an
00:14:30.660
indication that they may be testing more
00:14:32.220
than one thing
00:14:33.480
so taking a closer look
00:14:35.339
we can see if there's any overlap
00:14:37.920
each of these tests have this check
00:14:40.740
expect me to be a kind of mute
00:14:43.560
it looks like each of those are using an
00:14:45.480
expect to change block to send a mute
00:14:47.579
message and then checking this return
00:14:48.899
type
00:14:50.279
so this is an optional refactor it's
00:14:52.260
unrelated to letter subject but we can
00:14:53.880
take this opportunity if we want to to
00:14:55.320
remove that duplication of the type
00:14:56.639
check
00:14:59.220
zooming back out we can run these tests
00:15:01.079
to ensure that they pass I did they do
00:15:02.820
don't worry about it
00:15:06.420
then we can continue to inline let
00:15:08.399
methods
00:15:09.480
hide notifications and ARG notifications
00:15:11.639
are a couple of let methods that are
00:15:13.019
similarly named because they're being
00:15:14.519
passed as keyword arguments of similar
00:15:16.019
names so they're adding confusion just
00:15:17.760
by existing as opposed to being inline
00:15:19.980
in the calls so let's inline them right
00:15:22.079
away
00:15:26.579
doing that means we no longer need these
00:15:28.320
context blocks because they're no longer
00:15:29.639
providing a place to define those let
00:15:31.860
methods
00:15:33.540
so we can flatten them as well and just
00:15:35.220
take the meaningful context in their
00:15:37.199
text and append it into the IT
00:15:38.880
descriptions
00:15:42.540
now we can inline this me I like this
00:15:44.339
part of it because it looks like this is
00:15:45.660
going to be much shorter
00:15:49.980
we can inline this mute into each spec
00:15:52.440
as well and because it's used in this
00:15:55.320
before block we'll go ahead and inline
00:15:57.180
that now as well
00:16:01.800
note that at this point we're moving
00:16:03.779
some actual code into specs which was
00:16:05.519
obfuscated before that hide
00:16:06.779
notifications flag that was previously
00:16:08.880
being said in each of these context
00:16:10.079
blocks is now correctly set in the specs
00:16:12.899
so as you glance through the spec it's
00:16:14.399
easy to tell at a glance without needing
00:16:17.160
to find the hide notifications method
00:16:19.079
name which is highlighted like a method
00:16:20.459
name and not a Boolean and then search
00:16:22.560
backwards hoping to find the right
00:16:23.880
definition to find whether it's true or
00:16:25.440
false
00:16:28.860
so I'm going to fast forward a bit and
00:16:30.240
inline uh the last couple of lets
00:16:32.160
account and Target account
00:16:33.899
these are going to seem like they're
00:16:34.920
coming from nowhere because like the
00:16:37.259
original example I showed these let
00:16:38.519
methods are defined hundreds of lines
00:16:39.899
away from where they're being used this
00:16:41.699
particular file is only 650 lines as
00:16:44.100
opposed to 4 500.
00:16:46.320
uh but it uses these lets all over and
00:16:48.720
luckily it doesn't override them at all
00:16:50.160
so it's easy for us to determine which
00:16:51.899
ones to inline in this case it does beg
00:16:54.000
the question as to what benefit they're
00:16:55.019
providing by not being in line to begin
00:16:56.339
with
00:16:58.079
we're able to make the inline
00:16:59.160
definitions in place of methods in some
00:17:00.720
places and in others we use local
00:17:03.060
variables to replace the method
00:17:04.380
definition so that we can use that same
00:17:05.760
name to make assertions against
00:17:10.140
so let's take a look at one of those
00:17:11.220
refactored specs this is the before
00:17:13.260
example
00:17:14.640
uh it's extremely terse it tells us
00:17:17.339
almost nothing about what we're testing
00:17:21.059
we can kind of tell that we're making
00:17:22.919
expectations about a subject recall that
00:17:25.559
this is a test for a concern called
00:17:27.480
account interactions so we don't
00:17:29.100
actually even have a class that would
00:17:30.480
make some educated guess about what the
00:17:31.919
default subject would be with described
00:17:33.360
class.net
00:17:35.760
the innermost expectation is that we're
00:17:38.400
returning a mute but where that comes
00:17:40.200
from why it would be a mute we really
00:17:42.000
have no idea to find that we need to
00:17:43.980
scroll up in this file about 55 lines
00:17:45.840
the definition of subject Which is far
00:17:47.700
more than is what's going to appear on
00:17:49.380
most of your screens
00:17:52.440
we're also checking that a mute doesn't
00:17:54.059
change its height notification setting
00:17:55.620
where this mute is defined what its
00:17:57.539
context is or how it's related to the
00:17:59.460
subject are completely opaque to us
00:18:03.000
we also know that the be kind of
00:18:05.039
expectation is checking a return type
00:18:06.660
and that that expectation is duplicated
00:18:08.640
nine times in this file and is unrelated
00:18:10.260
to the main purpose of this example
00:18:11.760
which is to hide that test that hide
00:18:14.100
notifications flag
00:18:16.919
finally we have no hint that there's
00:18:19.020
code being executed as part of a before
00:18:20.580
block
00:18:21.660
in this block before it's ever run
00:18:25.080
after our refactor the test is
00:18:27.440
understandable in isolation every piece
00:18:30.179
of context every piece of work every
00:18:32.160
hidden step that was previously
00:18:33.419
elsewhere in this large file is now here
00:18:35.580
so we can understand and read through
00:18:37.260
exactly what's happening
00:18:44.460
for a lot of the same reasons as let I
00:18:46.500
avoid I recommend avoiding before or
00:18:49.440
after or around in most cases however at
00:18:53.280
the global level I think it makes a lot
00:18:54.600
of sense for running things like
00:18:55.799
database cleaner to run all tests and
00:18:57.419
transactions
00:18:58.799
web mock to disable up on network
00:19:00.720
connections and anything else that's
00:19:02.580
going to be run for every single spec or
00:19:05.400
even for an entire category like any
00:19:06.960
subdirectory as spec it's probably okay
00:19:08.580
to be using it before there
00:19:10.440
the smell comes when you're doing things
00:19:11.940
that are scoped to some describer
00:19:13.860
context block even though or even a spec
00:19:16.440
file
00:19:17.580
at the risk of repeating myself it makes
00:19:19.679
sense to repeat yourself in order to
00:19:21.660
have understandable tests
00:19:24.419
avoid hiding excessive setup in some
00:19:26.340
block so that it seems like things are
00:19:28.020
simpler than they are
00:19:30.419
what's worse about before than let is
00:19:32.940
that it's additive rather than replace
00:19:34.380
of a word that I looked up just that I
00:19:37.260
could use it
00:19:38.340
here
00:19:39.900
whereas redefining let or subject will
00:19:41.640
not execute the code that will have
00:19:43.919
would have been defined by the method on
00:19:45.480
that name outside the current scope
00:19:46.740
before after and around will combine
00:19:49.140
so this can lead to a lot of setup code
00:19:50.700
that's happening outside of the scope of
00:19:52.140
your test you're running and can be
00:19:53.820
difficult to track down what all of it
00:19:55.200
is
00:19:57.000
shared examples shared context behaves
00:20:00.000
like and similar rspec tools have the
00:20:02.039
same problem as letter before since
00:20:03.720
they're almost certainly using those
00:20:04.980
tools but additionally because they need
00:20:07.260
to use indirection so they can be
00:20:08.940
reusable they have the additional
00:20:10.740
problem that they explode the complexity
00:20:12.360
of code because they need to be run
00:20:14.940
every single time they're included so
00:20:16.559
they may be being run and running all of
00:20:19.080
their before blocks and all their let
00:20:20.340
blocks and all of their round blocks
00:20:23.460
a dozen times every time you include
00:20:25.559
them because they're being
00:20:27.179
they're being included in multiple
00:20:28.799
places
00:20:30.000
these hide complexity in the name of
00:20:31.559
decreased repetition and often require a
00:20:33.539
lot of their own setup to be used again
00:20:35.640
I'd recommend moving the important specs
00:20:37.380
for each class inline into the main spec
00:20:39.240
files rather than trying to extract them
00:20:41.400
using these tools
00:20:44.220
and for things like a module or a
00:20:46.080
concern rather than testing that every
00:20:47.880
single class that uses a module behaves
00:20:50.160
as if it does
00:20:51.480
try to test it directly or possibly
00:20:53.100
generate a test an example
00:20:55.860
implementation for the test that can be
00:20:57.960
used to exercise the module and serve as
00:20:59.880
a reference to show you exactly what
00:21:01.320
your dependencies are
00:21:04.380
so in summary use our spec but only the
00:21:07.380
good parts
00:21:08.340
don't use let don't use before and don't
00:21:11.039
use shared anything
00:21:13.260
once again I have been Caleb Hearth
00:21:14.820
thank you so much for coming to the talk
00:21:16.380
and if you'd like to ask questions or
00:21:19.020
discuss our spec test double Mastodon
00:21:21.360
Dungeons and Dragons
00:21:23.280
please do come find me in the hallway
00:21:25.679
I also want to thank my employer for
00:21:27.419
sending me to rubyconf this year if
00:21:28.919
you've ever felt frustrated when you get
00:21:31.140
stuck on a problem we want to help with
00:21:32.880
that let us know what topics you wish
00:21:34.559
there were more resources on such as
00:21:36.299
talks blog posts or screencasts by
00:21:38.820
taking this survey
00:21:41.880
testable loves pair programming because
00:21:43.980
it can help us to get unstuck if you'd
00:21:45.600
like to pair with a double agent please
00:21:46.740
request a free virtual pairing session
00:21:48.419
with a testable developer at this link
00:21:50.700
thank you very much