{"id":214,"date":"2009-07-10T11:08:58","date_gmt":"2009-07-10T10:08:58","guid":{"rendered":"http:\/\/blog.jteam.nl\/?p=214"},"modified":"2009-07-10T11:08:58","modified_gmt":"2009-07-10T10:08:58","slug":"testing-with-factories","status":"publish","type":"post","link":"https:\/\/trifork.nl\/blog\/testing-with-factories\/","title":{"rendered":"Testing with factories"},"content":{"rendered":"<p>On July 1st, Jelmer added a very useful blog post about <a href=\"http:\/\/blog.jteam.nl\/2009\/07\/01\/testing-the-database-layer\/\">testing the database layer<\/a> in which he suggested to use &#8220;insert statement&#8221; and &#8220;fixture&#8221; classes to provide a good way to insert test data into your database. I am also using that technique as I&#8217;m writing unit tests for the database layer. I have to say this really makes unit tests less work to write, more focussed and therefore more fun to write!<\/p>\n<p>Although this technique solves the challenges we have in database layer tests, we might encounter similar challenges when writing unit tests for other layers (such as the service or frontend layer). This is because such tests often also require &#8220;test data&#8221; you need to create. Only this time the test data is not in the form of database rows, but in the form of Java objects. Such objects need to be instantiated in a valid state and often depend on other objects. I find this quite similar to inserting rows into database tables having not null columns and\/or foreign key constraints.<br \/>\n<!--more--><\/p>\n<h2>The challenge<\/h2>\n<p>As an example I made up the following unit test (using JUnit):<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Test\npublic void testCalculateTotalOrderPrice() {\n    Address address = new Address(&quot;Some Street&quot;, &quot;13a&quot;, &quot;1234AB&quot;, &quot;City&quot;);\n    User owner = new User(&quot;Firstname&quot;, &quot;Lastname&quot;, address);\n    Order order1 = new Order(Status.SENT, owner, new BigDecimal(&quot;15&quot;));\n    Order order2 = new Order(Status.SENT, owner, new BigDecimal(&quot;35&quot;));\n\n    BigDecimal totalPrice = service.calculateTotalOrderPrice(Arrays.asList(order1, order2));\n\n    assertEquals(new BigDecimal(&quot;50&quot;), totalPrice);\n}\n<\/pre>\n<p>Here we test that the total price of two orders is correctly calculated. The only thing we care about in this unit test is the price of both orders. But as you can see, to create an Order in a valid state, we need to set the Status and the user who owns the order as well. But to create the owning User we have to create it in a valid state as well. And in turn a User needs a valid Address instance. Such dependencies are quite common in for example your domain model (Hibernate\/JPA entities).<\/p>\n<p>We will also soon find ourselves copying and pasting the four lines of Order instantiation code in other tests that also require one or more valid Order instances. So not only it requires a lot of code to create an Order, we also copy and paste the same code all over the place.<\/p>\n<h2>Factories<\/h2>\n<p>Inspired by the &#8220;insert statement&#8221; technique we want a similar class that can help our tests create Order instances and provide default values for properties we don&#8217;t care about. Let&#8217;s call such a helper class a &#8220;factory&#8221;. This should reduce test code and allows us to only care about the price and not about any other fields of the order, or the fields of any of the order&#8217;s dependencies. This is what the factory looks like:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic class OrderFactory {\n\n    private Status status;\n    private User owner;\n    private BigDecimal price;\n\n    public OrderFactory() {\n        \/\/ Initialize the factory with default values\n        status = Status.SENT;\n        owner = new UserFactory().newInstance();\n        price = new BigDecimal(&quot;9.95&quot;);\n    }\n\n    public Order newInstance() {\n        return new Order(status, owner, price);\n    }\n\n    public OrderFactory setPrice(BigDecimal price) {\n        this.price = price;\n        return this;\n    }\n}\n<\/pre>\n<p>A factory should always have a no-arguments constructor which initializes defaults used for objects created by this factory. This way you can instantiate a factory without supplying any values at all. If a test does want to supply values, setter methods can be used.<\/p>\n<p>Each factory is responsible for creating instances of a single class. This way you can easily instantiate this factory using only default values for the fields. Notice that the above factory delegates instantiating a new User to another factory. That UserFactory follows the exact same principle and should possibly delegate the creation of an Address to an AddressFactory. Each of these factories could be reused in other tests.<\/p>\n<p>Having the OrderFactory in place helps us write the same test in a more efficient way:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Test\npublic void testCalculateTotalOrderPrice() {\n    Order order1 = new OrderFactory().setPrice(new BigDecimal(&quot;15&quot;)).newInstance();\n    Order order2 = new OrderFactory().setPrice(new BigDecimal(&quot;35&quot;)).newInstance();\n\n    BigDecimal totalPrice = service.calculateTotalOrderPrice(Arrays.asList(order1, order2));\n\n    assertEquals(new BigDecimal(&quot;50&quot;), totalPrice);\n}\n<\/pre>\n<p>Now we don&#8217;t have to care about anothing other than the price of an Order. All other required properties an Order has, we don&#8217;t have to set in the unit test. Also, dependencies of an Order are taken care of by the OrderFactory. Notice that we used a fluent interface for the factory so we can write the code for creating an Order in one statement. The fluent interface also makes the code more readable. Feel free to add any number of setter methods to any factory, as long as you only call them when your test cares about the value being set. Each of the three factory classes needed for this test (OrderFactory, UserFactory and AddressFactory) can also be reused in other tests. For example in tests that work with Users or with Addresses. As with <em>InsertStatement<\/em>s never rely on defaults! (see <a href=\"http:\/\/blog.jteam.nl\/2009\/07\/01\/testing-the-database-layer\/\">Jelmer&#8217;s blog<\/a>) Any value your test relies on should be made explicit, even if it is the same value as the default.<\/p>\n<p>So as you can see, these &#8220;factories&#8221; use similar principles as the &#8220;insert statements&#8221;, but they apply to objects instead of database table rows. I have used factories for a while now and it makes writing unit tests take less time and more fun. Because once you have a lot of factories in place, new unit tests can easily (re)use them in other situations.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On July 1st, Jelmer added a very useful blog post about testing the database layer in which he suggested to use &#8220;insert statement&#8221; and &#8220;fixture&#8221; classes to provide a good way to insert test data into your database. I am also using that technique as I&#8217;m writing unit tests for the database layer. I have [&hellip;]<\/p>\n","protected":false},"author":115,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[10],"tags":[11,120],"class_list":["post-214","post","type-post","status-publish","format-standard","hentry","category-development","tag-java","tag-testing"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Testing with factories - Trifork Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/trifork.nl\/blog\/testing-with-factories\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Testing with factories - Trifork Blog\" \/>\n<meta property=\"og:description\" content=\"On July 1st, Jelmer added a very useful blog post about testing the database layer in which he suggested to use &#8220;insert statement&#8221; and &#8220;fixture&#8221; classes to provide a good way to insert test data into your database. I am also using that technique as I&#8217;m writing unit tests for the database layer. I have [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/trifork.nl\/blog\/testing-with-factories\/\" \/>\n<meta property=\"og:site_name\" content=\"Trifork Blog\" \/>\n<meta property=\"article:published_time\" content=\"2009-07-10T10:08:58+00:00\" \/>\n<meta name=\"author\" content=\"Tom van Zummeren\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tom van Zummeren\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/trifork.nl\/blog\/testing-with-factories\/\",\"url\":\"https:\/\/trifork.nl\/blog\/testing-with-factories\/\",\"name\":\"Testing with factories - Trifork Blog\",\"isPartOf\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#website\"},\"datePublished\":\"2009-07-10T10:08:58+00:00\",\"author\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/ae1748819f078cd2f65813bb689e9e0b\"},\"breadcrumb\":{\"@id\":\"https:\/\/trifork.nl\/blog\/testing-with-factories\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/trifork.nl\/blog\/testing-with-factories\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/trifork.nl\/blog\/testing-with-factories\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/trifork.nl\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Testing with factories\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/trifork.nl\/blog\/#website\",\"url\":\"https:\/\/trifork.nl\/blog\/\",\"name\":\"Trifork Blog\",\"description\":\"Keep updated on the technical solutions Trifork is working on!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/trifork.nl\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/ae1748819f078cd2f65813bb689e9e0b\",\"name\":\"Tom van Zummeren\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/882552d346390f25c0ceacb5b6076623?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/882552d346390f25c0ceacb5b6076623?s=96&d=mm&r=g\",\"caption\":\"Tom van Zummeren\"},\"url\":\"https:\/\/trifork.nl\/blog\/author\/tom\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Testing with factories - Trifork Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/trifork.nl\/blog\/testing-with-factories\/","og_locale":"en_US","og_type":"article","og_title":"Testing with factories - Trifork Blog","og_description":"On July 1st, Jelmer added a very useful blog post about testing the database layer in which he suggested to use &#8220;insert statement&#8221; and &#8220;fixture&#8221; classes to provide a good way to insert test data into your database. I am also using that technique as I&#8217;m writing unit tests for the database layer. I have [&hellip;]","og_url":"https:\/\/trifork.nl\/blog\/testing-with-factories\/","og_site_name":"Trifork Blog","article_published_time":"2009-07-10T10:08:58+00:00","author":"Tom van Zummeren","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Tom van Zummeren","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/trifork.nl\/blog\/testing-with-factories\/","url":"https:\/\/trifork.nl\/blog\/testing-with-factories\/","name":"Testing with factories - Trifork Blog","isPartOf":{"@id":"https:\/\/trifork.nl\/blog\/#website"},"datePublished":"2009-07-10T10:08:58+00:00","author":{"@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/ae1748819f078cd2f65813bb689e9e0b"},"breadcrumb":{"@id":"https:\/\/trifork.nl\/blog\/testing-with-factories\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/trifork.nl\/blog\/testing-with-factories\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/trifork.nl\/blog\/testing-with-factories\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/trifork.nl\/blog\/"},{"@type":"ListItem","position":2,"name":"Testing with factories"}]},{"@type":"WebSite","@id":"https:\/\/trifork.nl\/blog\/#website","url":"https:\/\/trifork.nl\/blog\/","name":"Trifork Blog","description":"Keep updated on the technical solutions Trifork is working on!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/trifork.nl\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/ae1748819f078cd2f65813bb689e9e0b","name":"Tom van Zummeren","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/882552d346390f25c0ceacb5b6076623?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/882552d346390f25c0ceacb5b6076623?s=96&d=mm&r=g","caption":"Tom van Zummeren"},"url":"https:\/\/trifork.nl\/blog\/author\/tom\/"}]}},"_links":{"self":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/users\/115"}],"replies":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/comments?post=214"}],"version-history":[{"count":0,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/214\/revisions"}],"wp:attachment":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/media?parent=214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/categories?post=214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/tags?post=214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}