| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>Testing :: Apache Isis</title> |
| <link rel="canonical" href="https://isis.apache.org/testing/2.0.0-M3/about.html"> |
| <meta name="generator" content="Antora 2.2.0"> |
| <link rel="stylesheet" href="../../_/css/site.css"> |
| <link rel="stylesheet" href="../../_/css/site-custom.css"> |
| <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i|Raleway:300,400,500,700,800|Montserrat:300,400,700" rel="stylesheet"> |
| <link rel="home" href="https://isis.apache.org" title="Apache Isis"> |
| </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="https://isis.apache.org"> |
| <span class="icon"> |
| <img src="../../_/img/isis-logo-48x48.png"></img> |
| </span> |
| <span>Apache Isis</span> |
| </a> |
| <button class="navbar-burger" data-target="topbar-nav"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <a class="navbar-end"> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Quick Start</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Starter Apps</span> |
| <a class="navbar-item" href="../../docs/latest/starters/helloworld.html">Hello World</a> |
| <a class="navbar-item" href="../../docs/latest/starters/simpleapp.html">Simple App</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Demos & Tutorials</span> |
| <a class="navbar-item" href="../../docs/latest/demo/about.html">Demo App</a> |
| <a class="navbar-item" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic (tutorial)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Resources</span> |
| <a class="navbar-item" href="../../docs/latest/resources/cheatsheet.html">Cheatsheet</a> |
| <a class="navbar-item" href="../../docs/latest/resources/icons.html">Icons</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Guides</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Development</span> |
| <a class="navbar-item" href="../../setupguide/latest/about.html">Setup Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Core</span> |
| <a class="navbar-item" href="../../userguide/latest/about.html">User Guide</a> |
| <a class="navbar-item" href="../../refguide/latest/about.html">Reference Guide</a> |
| <a class="navbar-item" href="../../testing/latest/about.html">Testing Guide</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Libraries</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">For Use in Apps</span> |
| <a class="navbar-item" href="../../subdomains/latest/about.html">Subdomain Libraries</a> |
| <a class="navbar-item" href="../../valuetypes/latest/about.html">Value Types</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Integrate between Apps</span> |
| <a class="navbar-item" href="../../mappings/latest/about.html">Bounded Context Mapping Libraries</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Other</span> |
| <a class="navbar-item" href="../../incubator/latest/about.html">Incubator</a> |
| <a class="navbar-item" href="../../legacy/latest/about.html">Legacy</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Components</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Viewers</span> |
| <a class="navbar-item" href="../../vw/latest/about.html">Wicket UI</a> |
| <a class="navbar-item" href="../../vro/latest/about.html">Restful Objects (REST)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Security</span> |
| <a class="navbar-item" href="../../security/latest/about.html">Security Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Persistence</span> |
| <a class="navbar-item" href="../../pjdo/latest/about.html">DataNucleus (JDO)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Extensions</span> |
| <a class="navbar-item" href="../../extensions/latest/about.html">Extensions Catalog</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Support</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Contact</span> |
| <a class="navbar-item" href="../../docs/latest/support/slack-channel.html">Slack</a> |
| <a class="navbar-item" href="../../docs/latest/support/mailing-list.html">Mailing Lists</a> |
| <a class="navbar-item" href="https://issues.apache.org/jira/browse/ISIS">JIRA</a> |
| <a class="navbar-item" href="https://stackoverflow.com/questions/tagged/isis">Stack Overflow</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Releases</span> |
| <a class="navbar-item" href="../../docs/latest/downloads/how-to.html">Downloads</a> |
| <a class="navbar-item" href="../../relnotes/latest/about.html">Release Notes</a> |
| <a class="navbar-item" href="../../docs/latest/archive/1-x.html">Archive (1.x)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Framework</span> |
| <a class="navbar-item" href="../../conguide/latest/about.html">Contributors' Guide</a> |
| <a class="navbar-item" href="../../comguide/latest/about.html">Committers' Guide</a> |
| <a class="navbar-item" href="../../core/latest/about.html">Core Design</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">ASF</a> |
| <div class="navbar-dropdown"> |
| <a class="navbar-item" href="http://www.apache.org/">Apache Homepage</a> |
| <a class="navbar-item" href="https://www.apache.org/events/current-event">Events</a> |
| <a class="navbar-item" href="https://www.apache.org/licenses/">Licenses</a> |
| <a class="navbar-item" href="https://www.apache.org/security/">Security</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| <hr class="navbar-divider"/> |
| <a class="navbar-item" href="https://whimsy.apache.org/board/minutes/Isis.html">PMC board minutes</a> |
| </div> |
| </div> |
| <a class="navbar-item" href="../../docs/latest/about.html"> |
| <span class="icon"> |
| <img src="../../_/img/home.png"></img> |
| </span> |
| </a> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body "> |
| <div class="nav-container" data-component="testing" data-version="2.0.0-M3"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-pagination"> |
| <a class="page-previous disabled" rel="prev" href="" title=""><span></span></a> |
| <a class="page-next disabled" rel="next" |
| href="" title=""><span></span></a> |
| <!-- |
| page.parent doesn't seem to be set... |
| <a class="page-parent disabled" rel="prev" href="" title=""><span></span></a> |
| --> |
| </div> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <h3 class="title"><a href="about.html">Testing Guide</a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="unittestsupport/about.html">Unit Test Support</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="integtestsupport/about.html">Integ Test Support</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="integtestsupport/domain-model-validator.html">Domain Model Validator</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="integtestsupport/swagger-exporter.html">Swagger Exporter</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="specsupport/about.html">BDD Spec Support</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="fixtures/about.html">Fixture Scripts</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Domain Services</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="fixtures/services/ExecutionParametersService.html">ExecutionParametersService</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="fixtures/services/FixtureScripts.html">FixtureScripts</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="fixtures/services/FixtureScriptsSpecificationProvider.html">FixtureScriptsSpecificationProvider</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="fakedata/about.html">Fakedata</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="h2console/about.html">H2 Console</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Domain Services</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="h2console/services/H2ManagerMenu.html">H2ManagerMenu</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="hsqldbmgr/about.html">HSQLDB Manager</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Domain Services</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="hsqldbmgr/services/HsqlDbManagerMenu.html">HsqlDbManagerMenu</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title">Testing Guide</span> |
| <span class="version">2.0.0-M3</span> |
| </div> |
| <ul class="components"> |
| <li class="component"> |
| <span class="title"> </span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../docs/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">BC Mappings Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../mappings/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Committers' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../comguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Contributors' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../conguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Design Docs</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../core/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Extensions Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../extensions/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Incubator Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../incubator/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">JDO/DataNucleus</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../pjdo/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Legacy Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../legacy/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Reference Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../refguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Release Notes</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../relnotes/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Restful Objects Viewer</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../vro/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Security Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../security/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Setup Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../setupguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Subdomains Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../subdomains/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component is-current"> |
| <span class="title">Testing Guide</span> |
| <ul class="versions"> |
| <li class="version is-current is-latest"> |
| <a href="about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">User Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../userguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Value Types Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../valuetypes/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Wicket Viewer</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../vw/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main role="main"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <a href="../../docs/2.0.0-M3/about.html" class="home-link"></a> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="about.html">Testing Guide</a></li> |
| <li><a href="about.html">Testing</a></li> |
| </ul> |
| </nav> |
| <div class="edit-this-page"><a href="https://github.com/apache/isis/edit/2.0.0-M3/testing/adoc/modules/ROOT/pages/about.adoc">Edit</a></div> |
| </div> |
| <article class="doc"> |
| <a name="section-top"></a> |
| <h1 class="page">Testing</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>If you are using Apache Isis to develop complex business-critical applications, then being able to write automated tests for those applications is massively important. |
| As such Apache Isis treats the topic of testing very seriously.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This guide describes those features available to you for testing your Apache Isis application.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="unit-tests-vs-integ-tests"><a class="anchor" href="#unit-tests-vs-integ-tests"></a>Unit tests vs Integ tests</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>We divide automated tests into two broad categories:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="unittestsupport/about.html" class="page">unit tests</a> exercise a single unit (usually a method) of a domain object, in isolation.</p> |
| <div class="paragraph"> |
| <p>Dependencies of that object are mocked out. These are written by a developer and for a developer; they are to ensure that a particular "cog in the machine" works correctly</p> |
| </div> |
| </li> |
| <li> |
| <p><a href="integtestsupport/about.html" class="page">integration tests</a> exercise the application as a whole, usually focusing on one particular business operation (action).</p> |
| <div class="paragraph"> |
| <p>These are tests that represent the acceptance criteria of some business story; their intent should make sense to the domain expert (even if the domain expert is "non-technical")</p> |
| </div> |
| <div class="paragraph"> |
| <p>For larger "modular monoliths", integration tests can also run against a particular vertical slice of the application. |
| The <a href="../../docs/2.0.0-M3/starters/simpleapp.html" class="page">SimpleApp</a> starter app demonstrates this technique.</p> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>To put it another way:</p> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Integration tests ensure that you are <strong><em>building the right system</em></strong></p> |
| </div> |
| <div class="paragraph"> |
| <p>Unit tests ensure that you are <strong><em>building the system right</em></strong>.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>Integration tests leverage Spring Boot’s integration testing infrastructure,in particular using <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html">@SpringBootTest</a>. |
| This configures and bootstraps the Apache Isis runtime, usually running against an in-memory database.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="integ-tests-vs-bdd-specs"><a class="anchor" href="#integ-tests-vs-bdd-specs"></a>Integ tests vs BDD Specs</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>We further sub-divide integration tests into:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>those that are implemented in Java and JUnit (we call these simply <em>"integration tests"</em>)<br></p> |
| <div class="paragraph"> |
| <p>Even if a domain expert understands the intent of these tests, the actual implementation will probably be pretty opaque to them. |
| Also, the only output from the tests is a (hopefully) green CI job</p> |
| </div> |
| </li> |
| <li> |
| <p>tests (or rather, specifications) that are implemented in a <em>behaviour-driven design</em> (BDD) language such as <a href="https://cucumber.io/">Cucumber</a>. |
| We call these <em>"BDD specs"</em>, and provide the <a href="specsupport/about.html" class="page">BDD spec support</a> module to makes Cucumber and <code>@SpringBootTest</code> work together.</p> |
| <div class="paragraph"> |
| <p>The natural language specification then maps down onto some glue code that is used to drive the application. |
| But the benefits of taking a BDD approach include the fact that your domain expert will be able to read the tests/specifications, and that when you run the specs, you also get documentation of the application’s behaviour ("living documentation").</p> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>It’s up to you whether you use BDD specs for your apps; it will depend on your development process and company culture. But if you don’t then you certainly should write integration tests: acceptance criteria for user stories should be automated!</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="simulated-ui-wrapperfactory"><a class="anchor" href="#simulated-ui-wrapperfactory"></a>Simulated UI (<code>WrapperFactory</code>)</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>When we talk about integration tests/specs here, we mean tests that exercise the domain object logic, through to the actual database. But we also want the tests to exercise the app from the users’s perspective, which means including the user interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For most other frameworks that would require having to test the application in a very heavy weight/fragile fashion using a tool such as <a href="http://docs.seleniumhq.org/">Selenium</a>, driving a web browser to navigate . In this regard though, Apache Isis has a significant trick up its sleeve. Because Apache Isis implements the naked objects pattern, it means that the UI is generated automatically from declared domain-objects, -views and -services. This therefore allows for other implementations of the UI.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <a href="../../refguide/2.0.0-M3/applib-svc/WrapperFactory.html" class="page"><code>WrapperFactory</code></a> domain service allows a test to wrap domain objects and thus to interact with said objects "as if" through the UI:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="testing:integtestsupport:_images/wrapper-factory.png"><img src="integtestsupport/_images/wrapper-factory.png" alt="wrapper factory" width="400px"></a> |
| </div> |
| <div class="title">Figure 1. Wrapper objects</div> |
| </div> |
| <div class="paragraph"> |
| <p>If the test invokes an action that is disabled, then the wrapper will throw an appropriate exception. |
| If the action is ok to invoke, it delegates through. |
| There’s more discussion on the wrapper factory in the <a href="integtestsupport/about.html#wrapper-factory" class="page">integ test support</a> chapter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>What this means is that an Apache Isis application can be tested end-to-end without having to deploy it onto a webserver; the whole app can be tested while running in-memory. |
| Although integration tests re (necessarily) slower than unit tests, they are not any harder to write (in fact, in some respects they are easier).</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="dependency-injection"><a class="anchor" href="#dependency-injection"></a>Dependency Injection</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Spring Boot will automatically inject dependencies into integration tests and services, and Apache Isis extends this to also inject services into every domain object (entity or view model). |
| This is most useful when writing unit tests; simply mock out the service and inject into the domain object.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are a number of syntaxes supported, but the simplest is to use <code>@javax.inject.Inject</code> annotation; for example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@javax.inject.Inject |
| CustomerRepository customers;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Domain services are discovered by Spring Boot, either explicitly referenced in the <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Import.html">@Import</a> annotation, or picked up from class path scanning of <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html">@ComponentScan</a>. |
| Any service annotated or meta-annotated with <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a> can be discovered; this includes classes annotated with Apache Isis' <a href="../../refguide/2.0.0-M3/applib-ant/DomainService.html" class="page">@DomainService</a>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="givenwhenthen"><a class="anchor" href="#givenwhenthen"></a>Given/When/Then</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Whatever type of test/spec you are writing, we recommend you follow the given/when/then idiom:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>given</strong> the system is in this state (preconditions)</p> |
| </li> |
| <li> |
| <p><strong>when</strong> I poke it with a stick</p> |
| </li> |
| <li> |
| <p><strong>then</strong> it looks like this (postconditions)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>A good test should be 5 to 10 lines long; the test should be there to help you reason about the behaviour of the system. |
| Certainly if the test becomes more than 20 lines it’ll be too difficult to understand.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The "when" part is usually a one-liner, and in the "then" part there will often be only two or three assertions that you want to make that the system has changed as it should.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For unit test the "given" part shouldn’t be too difficult either: just instantiate the class under test, wire in the appropriate mocks and set up the expectations. |
| And if there are too many mock expectations to set up, then "listen to the tests" …​ they are telling you your design needs some work.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Where things get difficult though is the "given" for integration tests; which is the topic of the next section…​</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="fixture-management"><a class="anchor" href="#fixture-management"></a>Fixture Management</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>In the previous section we discussed using given/when/then as a form of organizing tests, and why you should keep your tests small.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For integration tests though it can be difficult to keep the "given" short; there could be a lot of prerequisite data that needs to exist before you can actually exercise your system. |
| Moreover, however we do set up that data, but we also want to do so in a way that is resilient to the system changing over time.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The solution that Apache Isis provides is |
| <a href="fixtures/about.html" class="page">fixture scripts</a>, supported by a domain service (also) called <a href="#refguide:applib-cm:classes/super.adoc#FixtureScripts" class="page unresolved">Fixture Scripts</a>. |
| This defines a pattern (command pattern and composite pattern) with supporting classes to help ensure that the "data setup" for your tests are reusable and maintainable over time.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="fake-data"><a class="anchor" href="#fake-data"></a>Fake data</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>In any given test there are often quite a few variables involved, to initialize the state of the objects, or to act as arguments for invoking a method, or when asserting on post-conditions. |
| Sometimes those values are important (eg verifying that an <code>Order</code>'s state went from PENDING to SHIPPED, say), but often they aren’t (a customer’s name, for example). |
| Nevertheless all this data may need to be set up, especially in integration tests.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We want our tests to be easily understood, and we want the reader’s eye to be drawn to the values that are significant and ignore those that are not.</p> |
| </div> |
| <div class="paragraph"> |
| <p>One way to do this is to use random (or fake) values for any insignificant data. |
| This in effect tells the reader that "any value will do". |
| Moreover, if it turns out that any data won’t do, and that there’s some behaviour that is sensitive to the value, then the test will start to flicker, passing and then failing depending on inputs. |
| This is A Good Thing™.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Apache Isis provides the <a href="testing:fakedata:about.adoc">Fake Data</a> library to assist with this.</p> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Using fake data works very well with fixture scripts; the fixture script can invoke the business action with sensible (fake/random) defaults, and only require that the essential information is passed into it by the test.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="feature-toggles"><a class="anchor" href="#feature-toggles"></a>Feature Toggles</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Writing automated tests is just good development practice. |
| Also good practice is developing on the mainline (master, trunk); so that your continuous integration system really is integrating all code. |
| Said another way: <a href="http://martinfowler.com/bliki/FeatureBranch.html">don’t use branches</a>!</p> |
| </div> |
| <div class="paragraph"> |
| <p>Sometimes, though, a feature will take longer to implement than your iteration cycle. |
| In such a case, how do you use continuous integration to keep everyone working on the mainline without revealing a half-implemented feature on your releases?</p> |
| </div> |
| <div class="paragraph"> |
| <p>One option is to use <a href="http://martinfowler.com/bliki/FeatureToggle.html">feature toggle</a>s. |
| These let us decouple deployment (meaning shipping code into production) from release (meaning let users have access to and use that feature).</p> |
| </div> |
| <div class="paragraph"> |
| <p>At its simplest, a feature toggle could be a global variable disabling the functionality until fully ready, or it might even just be implemented using security. |
| More sophisticated implementations make access more dynamic, for example by granting access to "alpha" or canary users.</p> |
| </div> |
| <div class="admonitionblock warning"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-warning" title="Warning"></i> |
| </td> |
| <td class="content"> |
| TODO: v2: intention is to bring in incode-platform’s feature toggle library. |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| </article> |
| <aside class="article-aside toc" role="navigation"> |
| <p class="toc-title">On this page</p> |
| <div id="article-toc"></div> |
| </aside> |
| </main> |
| </div> |
| <footer class="footer"> |
| <div class="content"> |
| <div class="copyright"> |
| <p> |
| Copyright © 2010~2020 The Apache Software Foundation, licensed under the Apache License, v2.0. |
| <br/> |
| Apache, the Apache feather logo, Apache Isis, and the Apache Isis project logo are all trademarks of The Apache Software Foundation. |
| </p> |
| </div> |
| <div class="revision"> |
| <p>Revision: SNAPSHOT</p> |
| </div> |
| </div> |
| </footer> |
| <script src="../../_/js/site.js"></script> |
| <script async src="../../_/js/vendor/highlight.js"></script> |
| <script src="../../_/js/vendor/jquery-3.4.1.min.js"></script> |
| <script src="../../_/js/vendor/jquery-ui-1.12.1.custom.widget-only.min.js"></script> |
| <script src="../../_/js/vendor/jquery.tocify.min.js"></script> |
| |
| <script> |
| $(function() { |
| $("#article-toc").tocify( { |
| showEffect: "slideDown", |
| hashGenerator: "pretty", |
| hideEffect: "slideUp", |
| selectors: "h2, h3", |
| scrollTo: 120, |
| smoothScroll: true, |
| theme: "jqueryui", |
| highlightOnScroll: true |
| } ); |
| }); |
| </script> |
| </body> |
| </html> |