<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Katie Larson</title>
    <description>The latest articles on DEV Community by Katie Larson (@sleepycecy).</description>
    <link>https://dev.to/sleepycecy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178614%2F08dc8bd4-ccad-4d9e-8342-72b6fa8159f6.jpg</url>
      <title>DEV Community: Katie Larson</title>
      <link>https://dev.to/sleepycecy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sleepycecy"/>
    <language>en</language>
    <item>
      <title>Fruit Cart: Writing Tests, Part I</title>
      <dc:creator>Katie Larson</dc:creator>
      <pubDate>Sun, 07 Jul 2019 01:23:15 +0000</pubDate>
      <link>https://dev.to/sleepycecy/fruit-cart-writing-tests-part-i-ld9</link>
      <guid>https://dev.to/sleepycecy/fruit-cart-writing-tests-part-i-ld9</guid>
      <description>&lt;p&gt;Database up, the framework and tools in place, TDD process hammered out, all the magic ready--time to cast the spells! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UKs6UKum--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/hrw7U4H.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UKs6UKum--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/hrw7U4H.png" alt="Luna Lovegood from Harry Potter casting Patronus spell" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Unit . . . or so I thought&lt;/h2&gt;

&lt;p&gt;While we will be TDDing our code, we still had to decide on a basic architecture. For instance, if we want to test a Fruit model, well, then we have to decide that we need a Fruit model in the first place. There's a bit of a chicken or the egg problem: we're operating on the principle that the tests will drive production, but yet to even write the test we have to know what we're testing . . .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GB4t-jTb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/PEhP21h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GB4t-jTb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/PEhP21h.gif" alt="Animated egg hatching a chicken" width="382" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, in the example of the Fruit model, what comes first: the model or the tests? The chicken or the egg? The answer: the model. Sort of. In our collective brain it comes first. Tests and production code are dependent on each other. The way the tests are written certainly does determine the way the code is written, but for the tests to even be written in the first place, we have to decide on the basic architecture we're testing. In other words, we have to decide what we're testing. &lt;/p&gt;

&lt;p&gt;Jeff and I actually never went ahead and wrote a file without having the tests for it set up first, but we knew in our brain that what we file we would be testing.&lt;/p&gt;

&lt;p&gt;So we have to figure out what we're going to need and, perhaps more importantly, what we're not going to need. And that's where we run into YAGNI: You Aren't Gonna Need It.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mic-P3i6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/3SyxXgD.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mic-P3i6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/3SyxXgD.gif" alt="Black and white picture of baby throwing money out of a window" width="320" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;YAGNI comes from the Extreme Programming methodology and means that we  should only write the code that we need now, not what we &lt;em&gt;think&lt;/em&gt; we'll need in the future. Yes, we want our code to be extensible, but we also don't want to build out future functionality that is not what we're looking to deliver as a part of our minimum viable product. While this may not seem forward thinking, if we do too much anticipation outside the scope of the functioning product, we'll likely end up writing code that we don't need. &lt;/p&gt;

&lt;p&gt;For instance, say eventually user accounts and login is something we want Fruit Cart users to have and do. I go in and install the OAuth library with a Google strategy. Then I start building out functionality for creating a fruit. Suddenly I realize I didn't have a reason for users to log in. Why would they need to log in to create fruits? If all it takes to create fruit is a user account and anyone can have a user account, what is the point of having them log in? Hmmmm . . . seems like for MVP we're only going to need users to create fruit; they don't need an account. &lt;/p&gt;

&lt;p&gt;In the future, we may want this functionality if, say, we're going in the direction of an online store. But that's not what we're building at the moment. But, you may say, there is no harm in letting OAuth library or whatever login code we've written hang out in our codebase, so why not? And the answer is twofold: yes, there is a harm, but also, why waste our energy and resources on functionality that is not a part of the task at hand? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zzsuPhhp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/v3TxHea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zzsuPhhp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/v3TxHea.jpg" alt="Blonde woman in green shirt shrugging with a quizzical expression" width="480" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First the harm: the more dependencies you have, the more attack surfaces you have for bad actors. Although OAuth is a library we trust, it could be deprecated at some point and/or have vulnerabilities about which we know nothing. Besides, if you're not using it, why is it there?&lt;/p&gt;

&lt;p&gt;Also, any code we write does run the risk of tripping up our integration and functional tests. There may be unintended consequences to the way parts of our code interact with each other or subtle changes to the user journey. Keep the tests green!&lt;/p&gt;

&lt;p&gt;Second: cost of build. Why spend time on something we're specifically not building out right now? Building new functionality has a cost of time and human labor, so let's focus on what we know we want right now. We can address authorization and log in when we need those features. &lt;/p&gt;

&lt;p&gt;For more information on YAGNI, checkout this great &lt;a href="https://martinfowler.com/bliki/Yagni.html"&gt;Martin Fowler post&lt;/a&gt;. He uses a shipping insurance company from Minas Tirith as an example. Hope it fares better than those in Osgiliath.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--INoPHglR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/7ahxHZ6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--INoPHglR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/7ahxHZ6.gif" alt="Nazgul on dragon from Lord of the Rings movie flying in front of Frodo" width="500" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let's take a look at the structure of our API so we can even know what-in-the-what we're testing: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;ACTION: A call hits an endpoint, let's call it "/fruits", which triggers a database call that has us &lt;code&gt;getAll()&lt;/code&gt; fruits. Actions and routing to the correct calls will be handled by a controller, FruitCartController.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LOGIC: Since all the FruitCartController does is route and return responses, we need to something to handle actual business logic. For that, we have a FruitService. FruitService decides how we're going to get information from the database (not what information--that's decided by the controller). So we're going to have a handy method called &lt;code&gt;getAllFruits()&lt;/code&gt; which will do just that: get all fruits from the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DATA: So FruitService is going to call the database using a built-in JPA Repository method called findAll(). This FruitCartRepository is a mapper, and magically transforms data into the Java object of our choosing, in this case Fruit.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. &lt;/p&gt;

&lt;p&gt;So let's start at the beginning, with Marcus Aurelius . . . or the FruitCartController.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pya_VXjJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/ud0hK36.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pya_VXjJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/ud0hK36.jpg" alt="Marble bust of Marcus Aurelius" width="880" height="1062"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because I watched &lt;em&gt;Silence of the Lambs&lt;/em&gt; too many times, the quote "What is it in itself", which Hannibal Lector ascribes to Marcus Aurelius, continually pops into my head when trying to test. The full passage from &lt;em&gt;Meditations&lt;/em&gt; Book 8 reads: "What is this thing in itself, in its own constitution? What are its elements of substance and material, and of cause? What is its function in the world? What is its duration?"&lt;/p&gt;

&lt;p&gt;And in general, these are good things to ask code. What do we want this piece of code to do? What do we need it to do and what pieces of code do we need it to have? How long should it take to do these things? Expectations like these will guide our test-making &lt;/p&gt;

&lt;p&gt;Here's what we need from FruitCartController: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To have an endpoint that successfully returns an HTTP response with status of OK.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This endpoint will also need to return a list of all the fruits in the database.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cool. Let's write a test for the first bullet. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1eWS8kg4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/FxpdtiC.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1eWS8kg4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/FxpdtiC.gif" alt="Black and white image of bullet hitting concrete wall and shattering in slow motion" width="259" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Q: So in an HTTP request, how do we know a response was successful? &lt;br&gt;
A: A status code of 200, or OK.&lt;/p&gt;

&lt;p&gt;So we made a test for that in a class called FruitCartControllerTests. Spring provides us with MockMVC,  a servlet that mocks HTTP CRUD requests. If you're using IntelliJ (which I highly recommend for Java), you'll be prompted to import the correct library once you start writing code. Our final test reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldReturnHttpStatusOk&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/fruits"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isOk&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we run it, it fails. Great: we have our red. Time to get the green.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AB-83yco--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/7muNi57.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AB-83yco--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/7muNi57.jpg" alt="Wads of $100 bills" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now that we have the test, we need to write the code to make it pass. &lt;/p&gt;

&lt;p&gt;The obvious file needs to be created (FruitCartController) along with the obvious route ("/fruits"--the "/api" portion is namespacing since we'll also have routing with similar names for the front end and want to be as clear as possible when naming). Then all we do is pass it in the most obvious way, going back to Mr. Aurelius--what is it in itself? What is its behavior? Well, all we're requiring at the moment is that it return a 200 status, so let's go ahead and make an endpoint that does just that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Controller&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FruitCartController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/fruits"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt; &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OK&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run those tests and it should pass! Hurray! We have our green. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NmmUeACh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/lhk4wUN.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NmmUeACh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/lhk4wUN.gif" alt="animated dollars falling from sky" width="250" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now normally we'd refactor, either our test or our code, but in this case, the test is so small, it's hard to see where we would do that. The solution is pretty elegant and does exactly what it needs to do.&lt;/p&gt;

&lt;p&gt;So let's take the test one step further; after all, we don't just want a status--we want fruit!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sJq_WfrY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/PBI6p0A.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sJq_WfrY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/PBI6p0A.jpg" alt="Fruit" width="880" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll alter our test to require the return of an array of JSON fruit objects. It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{id: 1, name: "apple", description: "A fleshy red fruit"}, {id: 2, name: "banana", description: "A minion's favorite fruit"}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll expect to be able to access the first element in the array and get a name of "apple". Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@WebMvcTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FruitCartController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FruitCartControllerTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
  &lt;span class="nc"&gt;MockMvc&lt;/span&gt; &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldReturnAnArray&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/fruits"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isOk&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;isArray&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$[0].id"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$[0].name"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MockMVC performs that GET request, but on top of the status code of OK, we're also expecting some actual data. So of course, this promptly fails.&lt;/p&gt;

&lt;p&gt;Back at red. Let's make it pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ys16UCIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/rdaAG5X.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ys16UCIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/rdaAG5X.gif" alt="Nascar driving holding stop sign, then peering around it" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting the test to pass is actually going to be pretty easy: we make a Fruit model with some standard setters, getters, and a constructor, and then just hardcode the response we want directly into the return result in FruitCartController:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/fruits"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt; &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nc"&gt;Fruit&lt;/span&gt; &lt;span class="n"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruit&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OK&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's green. Time for the refactor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vHINohgO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/uW1XunU.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vHINohgO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/uW1XunU.gif" alt="Jennifer Lopez dancing in front of green rays of light" width="500" height="280"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;But is this really the way we want our system to work? The database isn't being queried, and we'd have to instantiate a ton of different Fruit objects within the controller, which is not its job. No. We need to make that database query to get all fruits. &lt;/p&gt;

&lt;p&gt;Now remember in our outline of the system architecture, the controller only handles the routing, telling the rest of the backend what data it actually wants to get. But it doesn't &lt;em&gt;actually get&lt;/em&gt; the data. Thus, its ability to fulfill its function depends on another layer of code: the service. Currently, FruitService doesn't even exist; we haven't written the code for it. But it sounds like we might have to start if we're going to get anywhere near how we actually want our controller to work. &lt;/p&gt;

&lt;p&gt;And now our little test has moved beyond unit testing. It's an integration test: we're testing that two layers--controllers and services--are interacting appropriately so as to return the desired result. &lt;/p&gt;

&lt;p&gt;So let's write some true unit tests; let's create our FruitService.&lt;/p&gt;

&lt;h2&gt;ABSOLUTE UNIT&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8HEnZ6fh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/evGtHVw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8HEnZ6fh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/evGtHVw.jpg" alt="Old black and white photo of a large ram" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially we thought FruitService would also be an integration test. After all, it is going to call on the FruitCartRepository, and that would need testing too, right? Well, not so much. &lt;/p&gt;

&lt;p&gt;FruitCartRepository, while indeed a file, is an interface. It's a contract between files or layers. And all the functionality we're using is contained by the JPA Repository. So in the end all we have is a file that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FruitCartRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing inside of it. All we have to do is tell Spring that this interface is a repository (the &lt;code&gt;@Repository&lt;/code&gt; handles that) and basically create it, specifying that it is mapping Fruit data from the fruit table onto Fruit objects and that the primary key in the database is an Integer datatype. All the actual data calls are provided by the library. &lt;/p&gt;

&lt;p&gt;So if we were to test our FruitCartRepository, we wouldn't actually be testing any code we wrote. We would be testing the JPA Repository's code. And that, friends, has already been tested. We just need to make sure it's being called right in our own custom code, which means testing the FruitService. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--drZT3G1E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/NGOTXXS.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--drZT3G1E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/NGOTXXS.jpg" alt="Two ladies serving lunch to school children" width="700" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Q: What is the core behavior of FruitService we need right now? &lt;br&gt;
A: We need it to return an array of fruits. &lt;/p&gt;

&lt;p&gt;What is the simplest thing it can return? An empty array! Frequently null or empty return values are the easiest way to start with testing. Baby steps.&lt;/p&gt;

&lt;p&gt;So we made another test file for our FruitService class and made a test to get an empty array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FruitServiceTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;FruitService&lt;/span&gt; &lt;span class="n"&gt;fruitService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fruitService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FruitService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldReturnEmptyArray&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruitService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllFruits&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we initialize a new FruitService called, originally enough, fruitService. Then we assert that it calls a method &lt;code&gt;getAllFruits()&lt;/code&gt; and that we expect that value to be an empty array.&lt;/p&gt;

&lt;p&gt;Run those tests, and boom: RED LIGHT.&lt;/p&gt;

&lt;p&gt;Time for that refactor.&lt;/p&gt;

&lt;p&gt;We go in, create that FruitService class, and create a method called &lt;code&gt;getAllFruits()&lt;/code&gt; to return &lt;code&gt;Arrays.asList()&lt;/code&gt;. That's it.&lt;/p&gt;

&lt;p&gt;Run those tests, and boom: GREEN LIGHT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IAsjtGBF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/quhXlCn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IAsjtGBF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/quhXlCn.gif" alt="Animation of stoplight turning red, then driver getting angry and speeding away" width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that's not really what we want, right? We want those fruits!&lt;/p&gt;

&lt;p&gt;So we re-write the test to look for a fruit in that array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldReturnArrayOfFruit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruitservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllFruits&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. We're trying to get the id from the first element in the array, which should be one.&lt;/p&gt;

&lt;p&gt;Run that test, and we're back at red.&lt;/p&gt;

&lt;p&gt;Now let's fix our FruitService. We replace the return value of &lt;code&gt;Arrays.asList()&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="nc"&gt;Fruit&lt;/span&gt; &lt;span class="n"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruit&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it: run the test, and the light is green.&lt;/p&gt;

&lt;p&gt;But is this really how we want it to do this? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hEoW0SCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/49vra81.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hEoW0SCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/49vra81.jpg" alt="Close up of head of Rodin's The Thinker statue" width="700" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're running into the same problem with our FruitService that we did with our FruitCartController. It's not querying the database, but creating objects right in its own logic, which is not what it should be doing. It should be querying the mapper (FruitCartRepository), which should query the database to get what it needs. It should then return an array of these objects. So what we need to test for is if it's calling the FruitCartRepository. We want to test it to be sure it's returning not only what we need, but doing it in the way we need it to. And for that we need to up our testing game.&lt;/p&gt;

&lt;p&gt;We need a couple of new superheroes: Mocks &amp;amp; Stubs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MFQP1OU4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/D2n90wj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MFQP1OU4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/D2n90wj.gif" alt="Cat dressed up as Puss 'n' Boots with smaller cat strumming a guitar behind them" width="500" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>java</category>
    </item>
    <item>
      <title>Fruit Cart: Testing Rules of the Game</title>
      <dc:creator>Katie Larson</dc:creator>
      <pubDate>Tue, 25 Jun 2019 23:03:42 +0000</pubDate>
      <link>https://dev.to/sleepycecy/fruit-cart-testing-rules-of-the-game-1k0</link>
      <guid>https://dev.to/sleepycecy/fruit-cart-testing-rules-of-the-game-1k0</guid>
      <description>&lt;p&gt;After a config full of "code holes" and discussion about what, if anything, we needed to add to our original stack, we were ready to start our first user story: the Landing Page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpjiaH0I.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpjiaH0I.gif" alt="grey cat landing in snow in slow motion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our initial page is designed to show the navbar along with a list of all the fruits in our database. The user story is pretty simple, done in the "As, wants to, so that" format: As a user, I want to visit the landing page so that I can see a list of all current fruits. We have a context (user), an action (visiting the landing page), and a value (seeing the current fruits). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDsuoWB2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDsuoWB2.jpg" alt="hand drawn mock up of our landing page on whiteboard with red marker; lists all fruits with navbar at top"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acceptance criteria are few and equally simple: if there are no fruits, user should should see an "Add Fruits" message; if there are fruits, the user should see the fruits. (In retrospect, error handling should also have been an AC: if the page fails to load, an error message is displayed.)&lt;/p&gt;

&lt;p&gt;Fruits currently have just an id, name, and description--pretty simple data. Now the navbar is a separate card, so we're just focusing on the listing of fruit.&lt;/p&gt;

&lt;p&gt;Next step: task it out. What do we need to do and what files do we need to touch to fulfill the ACs and finish the card? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1nfXY3d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1nfXY3d.gif" alt="Homer Simpson checking off list of things to do"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the database up, we need a fruit model (our backend is object-oriented), fruit repository to handle mapping of SQL to the model, fruit service to handle business logic, and fruit controller to provide actual endpoints and handle calls. We'll have to create directories and folders for all of that in the same package. But first things first: the tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fqr8mrgl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fqr8mrgl.gif" alt="Printer printing out sheet after sheet in top tray reading "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The primary goal of this project is to create a simple CRUD app using TDD, or test drive development. Here's what this means in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;We write tests first&lt;/em&gt; Tests are the first lines of code we write whenever we start a new piece of functionality. Hence . . .&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tests define production code&lt;/em&gt; They define what code is written in the first place. They drive the code. For example: we know our fruit cart service needs to return a fruit item with a name "apple" when the &lt;code&gt;getAllFruits()&lt;/code&gt; method is called. So we write a test that calls &lt;code&gt;getAllFruits()&lt;/code&gt;, with the result expected to include the string "apple". This allows us to keep results and expectations in mind, and, ultimately become more value driven. After all, if you don't know what you want your code to do, why write it in the first place?&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Tests are just as important as production code&lt;/em&gt; We spend equal time writing good tests and good code. They're not an after thought, and they allow us to write cleaner, more focused code in an incremental manner called . . .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FV51EjpE.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FV51EjpE.gif" alt="Polar bear cub coming towards camera"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Baby steps&lt;/em&gt; We take it one step at a time. If it's easiest to make the service pass the above test by hardcoding a return value of a string "apple", then that's what we do. The test will pass, and we can move on to the next step: refactoring.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Red, Green, Refactor&lt;/em&gt; Ah, the core of TDD. Write your test, make it fail (red). Write your code, and, in the easiest way possible, make it pass (green). This initially may mean hardcoding, just like in the example above. Then refactor your code. Hardcoding values is a code smell, so in this case, you would refactor it out. Every time you make a change that could alter the return value, run the tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYRnNfQJ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYRnNfQJ.gif" alt="Stop light flipping between just red and green rapidly"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Change either your test or code, not both&lt;/em&gt; Now tests can be refactored just as much as code can. But you don't want to make changes to both, run your tests, and watch them fail. Then you won't know what actually failed: the newly refactored code or the newly refactored tests. Furthermore, you may actually be changing what behavior your tests are expecting, making previously solid code fail. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9c642f4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9c642f4.png" alt="Diagram of the test pyramid indicating UI tests at the top are most expensive and slowest and unit tests at the bottom are quickest and cheapest. Integration tests sit in the middle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The Testing Pyramid&lt;/em&gt; We'll be following the classic testing pyramid.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Unit tests will make up the bulk of our test suite&lt;/em&gt; These tests run against discrete  methods and have concrete expectations. For example, if I run the &lt;code&gt;getAllFruits()&lt;/code&gt; method that gets all fruit information from the database, I should have a solid expectation of its return value (eg. an array of fruit objects, one of which contains the name "apple"). Their advantages are that they are fast and small: when they fail, they fail quickly, so we get near instant feedback (assuming we run our tests regularly); and when they fail, they fail for a single piece of functionality so it's quite easy to target what line of code failed. Plus, they take fewer resources to run. JUnit with the Hamcrest library will be our friends here for the backend, along with Jest and Enzyme for the React frontend. &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FmKxvIO3.png" alt="JUnit Logo"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1yxXW3t.jpg" alt="Hamcrest Logo"&gt; &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1OHWR8X.png" alt="Jest Logo"&gt; &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FRCHnCvb.png" alt="AirBNB Logo"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Integration tests form our middle ranks&lt;/em&gt; These are slightly more expensive in terms of computing resources, but they test the connections between the moving parts. For instance, our controller tests are actually integration tests--when we hit an endpoint, the controller calls the service which calls the repository which calls the database to get the fruits. Several methods across multiple classes are called here, and we want to make sure everything works. These are larger, require mocking and stubbing (which we will return to in a different post), and span across multiple classes. They make sure everything works together, but when they fail, they take longer to do so, and it can be hard to tell what, exactly, is failing. We'll add Mockito to JUnit for these tests. &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FIEL1OYP.jpg" alt="Mockito logo"&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Functional or UI tests sit at the top&lt;/em&gt; They test everything--user interface, database, services, etc--to make sure it all works together correctly. For instance, when a user lands on our page, they should see all the fruits listed. That's the front and backend pieces all working together for a single result. These tests take longer and may require a zombie web browser to be spun up and simulate user interactions. When they fail, it can be extremely difficult to tell why. Selenium will be our tool of choice to automate these.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXsv7yk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXsv7yk0.png" alt="Selenium logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those are the rules! Let the (fruity) games begin!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>java</category>
      <category>agile</category>
    </item>
    <item>
      <title>Fruit Cart: Config</title>
      <dc:creator>Katie Larson</dc:creator>
      <pubDate>Fri, 21 Jun 2019 16:09:06 +0000</pubDate>
      <link>https://dev.to/sleepycecy/fruit-cart-config-31f6</link>
      <guid>https://dev.to/sleepycecy/fruit-cart-config-31f6</guid>
      <description>&lt;p&gt;Stories sliced, goals set, it is now time to spin up the cart.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Ia-0G1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/hMwNmp6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Ia-0G1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/hMwNmp6.gif" alt="woman spinning a rolling shopping cart and catching it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Config and project start has always been awkward for me. You only start a project once during its duration, so all the steps you have to take to get it code-ready are in neither my muscle memory nor my brain memory. After all, I'm not constantly starting greenfield projects.&lt;/p&gt;

&lt;p&gt;But start we must. So in the beginning, here's what we did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Bootstrapped a Gradle project using &lt;a href="https://start.spring.io/"&gt;https://start.spring.io/&lt;/a&gt; We added the JPA, Devtools, and Postgres dependencies, which you can search for on the site. We will be using MyBatis to run the migrations, but not as a mapper; that will be handled "under the hood" by the JPA repository library.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initiated a Git repo (remote and local) for Fruit Cart and performed our first commit of the initial codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed and ran a Postgres server. Followed these instructions to create a new database 'fruitcart' with superuser 'fruitcart':&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Start postgres server and setup database&lt;br&gt;
    * check that the fruitcart superuser exists&lt;br&gt;
      run "psql -c '\du'"&lt;br&gt;
    * if user does not exist&lt;br&gt;
        run "c" (no need to set a password, defaults to 'postgres')&lt;br&gt;
    * create database fruitcart&lt;br&gt;
      run "./gradlew initdb"&lt;br&gt;
    * create migrations for fruit table with columns id, description, and &lt;br&gt;
      name. Run "./gradlew createdb"&lt;br&gt;
    * to add some data&lt;br&gt;
      run "psql -h localhost -U fruitcart --password -d fruitcart &amp;lt; db/backup.sql"&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ran a clean build to see if there were any errors (spoiler alert: there were--database wasn't configured properly).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created Gradle tasks to initialize and create our database on clean build. After we got our database up correctly and running on port :5432, we were ready to start with our first tests. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But let's back up a second. Let's talk takeaways.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ME_TzCZ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/WxJqbwf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ME_TzCZ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/WxJqbwf.gif" alt="golden retriever dog trotting with a paper bag"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, migrations must be created and run from the command line in the same directory where your database environment is located. I did know this before, but it bears repeating because I routinely forget it (hey, this blog is a resource for me too).&lt;/p&gt;

&lt;p&gt;Command is:&lt;br&gt;
&lt;code&gt;./mybatis/bin/migrate new name-of-migration&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should create a file (the name of which begins with a timestamp--migrations run in the order in which they were created) in the scripts directory. Use this to add you SQL statements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--za8za4Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JXrQnuq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--za8za4Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JXrQnuq.jpg" alt="back of a bald man's head with fingers plugging both ears"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second: If you treat it right, .gitignore is your friend.&lt;/p&gt;

&lt;p&gt;So there are certain files we don't want to appear in our remote repo. I usually think of .gitignore as a convenient place to hide secrets, but I think more practically it allows us to hide those pieces of our project that are specific to our local builds and not necessary for building our project in other environments, such as those that track changes in our workspace or build. &lt;/p&gt;

&lt;p&gt;We used &lt;a href="https://gitignore.io/"&gt;https://gitignore.io/&lt;/a&gt; to generated the correct .gitignore file for IntelliJ, our IDE for this project. It's a little overkill: we don't have Jira or the Crashalytics plugin enabled (pure IntelliJ CE level for us), but it gives us a good sense of what should be included. So we just copied and pasted that into our very own .gitignore. And all is well.&lt;/p&gt;

&lt;p&gt;Well, not so much for Jeff.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MUmEsG7G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/lfLyFz8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MUmEsG7G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/lfLyFz8.gif" alt="Lego man typing on computer, then pounding on computer, then throwing computer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the .idea files--workspace.xml--kept escaping from the .gitignore. He would try and commit/push his code, and there would be a failure: there were changes to his workspace.xml file that weren't tracked. But of course there were and of course it wouldn't be tracked: it's a file that tracks his location in the IDE and other internal structures particular to his workspace. For some reason, .gitignore was not telling git that this file shouldn't be tracked.&lt;/p&gt;

&lt;p&gt;Turns out, if you already committed that file and pushed it to your remote repo, it will haunt you. In Jeff's words, "It's a piece sh**".&lt;/p&gt;

&lt;p&gt;Solution: Delete the .idea folder (it will be generated automatically by IntelliJ anyway), commit your changes, then add .idea/workspace.xml to your .gitignore, and add/commit/push all that up. &lt;/p&gt;

&lt;p&gt;tl;dr: if a file has already been committed to your repo it will be automatically tracked regardless of whether or not you put it in .gitignore&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EMOrMQ59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/XLuwDE2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EMOrMQ59--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/XLuwDE2.jpg" alt="glowing 3D table rendering of a database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Third: there may be manual set up of SQL with your Postgres DB. &lt;/p&gt;

&lt;p&gt;Our build was failing. Turns out our DB wasn't being created. So weird, given that Postgres was running (I think it always is on my machine; that and Docker). But the database wasn't being created. It just wasn't there.&lt;/p&gt;

&lt;p&gt;Turns out we had to create a shell script to actually create the database, and when we did we created an owner, fruitcart, that didn't actually exist.&lt;/p&gt;

&lt;p&gt;Our shell script made the createdb function just fine, and we executed the task in our build, but the database would actually fail because there was no superuser or even user with write permissions. Basically we hadn't followed the first two * of the instructions at the beginning of this post. Once we had, our fruit cart snapped into existence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wrs3PbMU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/pgDcke5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wrs3PbMU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/pgDcke5.gif" alt="Tina Fey giving herself a high five"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now all this took so much longer than we thought. And this is going to be a running theme with us: we spike, go into internet wormholes, and spend a lot of time exploring. We looked at getting Jetty happening, discarded Jetty after numerous failures. We spent a long time with workspace.xml. We tinkered in Postgres. It's getting better. But it's hard to even know what questions to ask when you're learning. It's hard to even know where to look when you don't know what you don't know.&lt;/p&gt;

&lt;p&gt;And after all, that's what this is: learning.&lt;/p&gt;

</description>
      <category>java</category>
      <category>sql</category>
    </item>
    <item>
      <title>Fruit Cart: Inception</title>
      <dc:creator>Katie Larson</dc:creator>
      <pubDate>Wed, 12 Jun 2019 22:24:40 +0000</pubDate>
      <link>https://dev.to/sleepycecy/fruit-cart-inception-1ne3</link>
      <guid>https://dev.to/sleepycecy/fruit-cart-inception-1ne3</guid>
      <description>&lt;p&gt;The Fruit Cart project was born from one three-hour training course, the desire to create an entire application strictly test-driven development (TDD) style, and, well, Jeff. Jeff is my pair for this project. It's his little blueberry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6F7bN9J2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/PsZ6puh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6F7bN9J2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/PsZ6puh.gif" alt="blueberry falling down a pile of fresh raspberries" width="500" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this series, I'm going to be walking through our process of creating a SPA using ReactJS that fetches info from a Java/Spring Boot API and Postgres database. It's entirely test-driven: our tests write our code and take just as much primacy in the process as functionality. We'll be using JUnit with the Hamcrest library, Jest with Enzyme, and (eventually) Selenium. &lt;/p&gt;

&lt;p&gt;Now it's not my intention to create a tutorial that can be repeated step-by-step. My aim is to reflect on the process and reinforce what I'm learning. For instance, what were the pain points? What did we have to research? Which resources were valuable and why? Where were their pain points? What do we wish we had?&lt;/p&gt;

&lt;p&gt;So here's where we started: &lt;/p&gt;

&lt;h1&gt;
  
  
  Inception
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4pNST5ZF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/ZQPI4eE.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4pNST5ZF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/ZQPI4eE.gif" alt="Inception movie gif of room being created through smoke" width="245" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm a fairly organized person, so I like to know what I need to do, when I need to do it, and why I need to do it. Otherwise I find myself in what I call a "code hole": an internet wormhole composed of nothing but docs, Stack Overflow posts, Baeldung pages, and DZone tutorials. By the time I emerge, I frequently have lost sight of what I was researching in the first place. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EWLYZpvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/YIG7gzN.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EWLYZpvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/YIG7gzN.gif" alt="golden wormhole" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To avoid a code hole, we split our very basic CRUD cart into user stories. It's an easy way to task out what, exactly, we want to happen.&lt;/p&gt;

&lt;p&gt;We ended up with 5 stories detailing the 7 RESTful routes (index, show, new, create, edit, update, destroy), 1 story for navigation, and 2 cards related to image uploads. Here's an overview of what we want the user to do on the cart:&lt;/p&gt;

&lt;p&gt;When a user reaches the landing page and there are fruits in the &lt;br&gt;
   database, they should see a list (name, description) of all those &lt;br&gt;
   fruits. Otherwise, if there are no fruits, they see the Banana Man and &lt;br&gt;
   are prompted to add a fruit. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9vaB8w12--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/dMimtHT.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9vaB8w12--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/dMimtHT.gif" alt="peanut butter and jelly time banana man dancing" width="300" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user should also see a navbar with "Add Fruit" and "Home" as &lt;br&gt;
   options; the navbar will be visible on any "page" in the Fruit Cart &lt;br&gt;
   app. Each fruit description and name is a link that routes users to &lt;br&gt;
   the show page for that particular fruit (see #4 below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PpGwDIF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/DsuoWB2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PpGwDIF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/DsuoWB2.jpg" alt="hand-drawn sketch of list of fruits with navbar" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user clicks on the "Add Fruit" message or "Add Fruit" option &lt;br&gt;
   in the navbar, it takes them to a form with name and description &lt;br&gt;
   fields with the save button. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ILpRNZbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/0rhSF45.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ILpRNZbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/0rhSF45.jpg" alt="hand-drawn sketch of form for submitting a new fruit" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon submission of a completed fruit form (i.e. when the user clicks &lt;br&gt;
   "save"), the fruit is created, and the user is taken to the show page &lt;br&gt;
   for that fruit.&lt;/p&gt;

&lt;p&gt;The show page displays the name and description of the fruit, as well &lt;br&gt;
   as a button to edit the fruit. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TTE9Ljxd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/qjAZHry.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TTE9Ljxd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/qjAZHry.jpg" alt="hand-drawn sketch of page showing information for fruit" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user clicks the "edit" button, they are directed to the edit &lt;br&gt;
   form with pre-filled information in the name and description fields. &lt;br&gt;
   They edit, then submit the form to update the fruit. They are then &lt;br&gt;
   redirected to the newly-updated show page for the fruit they just &lt;br&gt;
   edited. If they were to click on the home link in the navbar, they &lt;br&gt;
   would be redirected to the landing page, now with any new or updated &lt;br&gt;
   fruits they have created.&lt;/p&gt;

&lt;p&gt;And that's it! Additional functionality will include the ability to upload and insert images, but that's likely for version 2.0.&lt;/p&gt;

&lt;p&gt;Now it's not super complicated; there's no log in or log out functionality or social media aspect, but that's not the point. The basics are the point: TDD and RESTful APIs, small React components and minimal dependencies, Java and Spring Boot. The experience is the point.&lt;/p&gt;

&lt;p&gt;Next up: Landing page! Let's see all those beautiful fruits. 🍉 🍌🍎 🍍 🍒  &lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>java</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
