CINXE.COM
Overriding dependencies in a test with playframework and guice
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Overriding dependencies in a test with playframework and guice</title> <meta name="viewport" content="width=device-width"> <link href="/assets/css/style.css" rel="stylesheet" /> <!-- favicon code start, by https://favicon.io/favicon-generator --> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="manifest" href="/site.webmanifest"> <!-- favicon code end --> </head> <body> <div id="header-outer"> <header id="header"> <h1><a href="/">Michael Pollmeier ~ dev blog</a></h1> <nav> <ul> <li><a href="/">blog posts</a></li> <li><a href="/presentations">presentations</a></li> <li><a href="http://twitter.com/pollmeier">twitter</a></li> <li><a href="/feed.xml">rss</a></li> <li><a href="/about">about me</a></li> </ul> </nav> </header> </div> <div id="page"> <div id="content"> <article class="post"> <h1><a href="/2015/09/25/playframework-guice-di">Overriding dependencies in a test with playframework and guice</a></h1> <p class="meta"> Posted on <span class="postdate">Sep 25, 2015</span><br/> tags: <!-- <a href="/tags.html#scala">scala</a> --> scala<span class="tag-separator">,</span> <!-- <a href="/tags.html#recipe">recipe</a> --> recipe<span class="tag-separator">,</span> <!-- <a href="/tags.html#test">test</a> --> test<span class="tag-separator">,</span> <!-- <a href="/tags.html#playframework">playframework</a> --> playframework </p> <div class="post-content"><p><a href="https://www.playframework.com/">Playframework</a> recently made <a href="https://github.com/google/guice">guice</a> its’ default dependency injection (DI) framework. So I was looking for a simple example where a controller defines a dependency which then get’s overridden for a FakeApplication in a test. I expected a simple gist in the docs for this very common (I thought) use case, but didn’t find one. Here is what I ended up with, which is based on <a href="http://www.scalatest.org/plus/play">ScalaTest + Play</a>.</p> <p>The nice thing about this setup is that it always tests the whole app, incl. the routing. Often developers only test a specific controller method, which leaves some space for bugs.</p> <p>app/controller/PersonController.scala:</p> <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Hello</span> <span class="o">{</span> <span class="k">def</span> <span class="nf">sayHello</span><span class="o">(</span><span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="s">"Hello "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">}</span> <span class="k">class</span> <span class="nc">PersonController</span> <span class="nd">@Inject</span><span class="o">()</span> <span class="o">(</span><span class="n">hello</span><span class="k">:</span> <span class="kt">Hello</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Controller</span> <span class="o">{</span> <span class="k">def</span> <span class="nf">index</span> <span class="k">=</span> <span class="nc">Action</span> <span class="o">{</span> <span class="nc">Ok</span><span class="o">(</span><span class="nv">hello</span><span class="o">.</span><span class="py">sayHello</span><span class="o">(</span><span class="s">"michael"</span><span class="o">))</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>test/ApplicationTest.scala:</p> <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">controllers._</span> <span class="k">import</span> <span class="nn">org.scalatest._</span> <span class="k">import</span> <span class="nn">org.scalatestplus.play._</span> <span class="k">import</span> <span class="nn">play.api.inject.bind</span> <span class="k">import</span> <span class="nn">play.api.inject.guice.GuiceInjector</span> <span class="k">import</span> <span class="nn">play.api.inject.guice.GuiceableModule</span> <span class="k">import</span> <span class="nn">play.api.test._</span> <span class="k">import</span> <span class="nn">play.api.test.Helpers._</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">MyPlaySpec</span> <span class="k">extends</span> <span class="nc">WordSpec</span> <span class="k">with</span> <span class="nc">Matchers</span> <span class="k">with</span> <span class="nc">OptionValues</span> <span class="k">with</span> <span class="nc">WsScalaTestClient</span> <span class="k">class</span> <span class="nc">GermanHello</span> <span class="k">extends</span> <span class="nc">Hello</span> <span class="o">{</span> <span class="k">override</span> <span class="k">def</span> <span class="nf">sayHello</span><span class="o">(</span><span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="s">"Hallo "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">}</span> <span class="k">class</span> <span class="nc">ApplicationTest</span> <span class="k">extends</span> <span class="nc">MyPlaySpec</span> <span class="k">with</span> <span class="nc">OneAppPerTestWithOverrides</span> <span class="o">{</span> <span class="k">override</span> <span class="k">def</span> <span class="nf">overrideModules</span> <span class="k">=</span> <span class="nc">Seq</span><span class="o">(</span> <span class="n">bind</span><span class="o">[</span><span class="kt">Hello</span><span class="o">].</span><span class="py">to</span><span class="o">[</span><span class="kt">GermanHello</span><span class="o">]</span> <span class="o">)</span> <span class="s">"render the index page"</span> <span class="n">in</span> <span class="o">{</span> <span class="k">val</span> <span class="nv">home</span> <span class="k">=</span> <span class="nf">route</span><span class="o">(</span><span class="nc">FakeRequest</span><span class="o">(</span><span class="nc">GET</span><span class="o">,</span> <span class="s">"/"</span><span class="o">)).</span><span class="py">get</span> <span class="nf">status</span><span class="o">(</span><span class="n">home</span><span class="o">)</span> <span class="n">shouldBe</span> <span class="nc">OK</span> <span class="nf">contentAsString</span><span class="o">(</span><span class="n">home</span><span class="o">)</span> <span class="n">shouldBe</span> <span class="s">"Hallo michael"</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>test/OneAppPerTestWithOverrides.scala:</p> <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">org.scalatestplus.play</span> <span class="k">import</span> <span class="nn">play.api.Application</span> <span class="k">import</span> <span class="nn">play.api.inject.guice.GuiceApplicationBuilder</span> <span class="k">import</span> <span class="nn">play.api.inject.bind</span> <span class="k">import</span> <span class="nn">play.api.inject.guice.GuiceableModule</span> <span class="k">import</span> <span class="nn">play.api.test._</span> <span class="k">import</span> <span class="nn">org.scalatest._</span> <span class="k">trait</span> <span class="nc">OneAppPerTestWithOverrides</span> <span class="k">extends</span> <span class="nc">SuiteMixin</span> <span class="o">{</span> <span class="k">this:</span> <span class="kt">Suite</span> <span class="k">⇒</span> <span class="kt">def</span> <span class="kt">overrideModules:</span> <span class="kt">Seq</span><span class="o">[</span><span class="kt">GuiceableModule</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Nil</span> <span class="k">def</span> <span class="nf">newAppForTest</span><span class="o">(</span><span class="n">testData</span><span class="k">:</span> <span class="kt">TestData</span><span class="o">)</span><span class="k">:</span> <span class="kt">Application</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">GuiceApplicationBuilder</span><span class="o">()</span> <span class="o">.</span><span class="py">overrides</span><span class="o">(</span><span class="n">overrideModules</span><span class="k">:</span> <span class="k">_</span><span class="kt">*</span><span class="o">)</span> <span class="o">.</span><span class="py">build</span> <span class="k">private</span> <span class="k">var</span> <span class="n">appPerTest</span><span class="k">:</span> <span class="kt">Application</span> <span class="o">=</span> <span class="k">_</span> <span class="k">implicit</span> <span class="k">final</span> <span class="k">def</span> <span class="nf">app</span><span class="k">:</span> <span class="kt">Application</span> <span class="o">=</span> <span class="n">synchronized</span> <span class="o">{</span> <span class="n">appPerTest</span> <span class="o">}</span> <span class="k">abstract</span> <span class="k">override</span> <span class="k">def</span> <span class="nf">withFixture</span><span class="o">(</span><span class="n">test</span><span class="k">:</span> <span class="kt">NoArgTest</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span> <span class="n">synchronized</span> <span class="o">{</span> <span class="n">appPerTest</span> <span class="k">=</span> <span class="nf">newAppForTest</span><span class="o">(</span><span class="n">test</span><span class="o">)</span> <span class="o">}</span> <span class="nv">Helpers</span><span class="o">.</span><span class="py">running</span><span class="o">(</span><span class="n">app</span><span class="o">)</span> <span class="o">{</span> <span class="nv">super</span><span class="o">.</span><span class="py">withFixture</span><span class="o">(</span><span class="n">test</span><span class="o">)</span> <span class="o">}</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>A full application (and test) is <a href="https://github.com/mpollmeier/play-scala-di">here</a>, and the discussion on the mailinglist <a href="https://groups.google.com/forum/#!topic/play-framework/gW8FXC3K30E">here</a>. More details on guice DI in playframework are in the <a href="https://www.playframework.com/documentation/2.4.x/ScalaTestingWithGuice">documentation</a></p> <p>PS: another handy tipp: if you want to get the used binding for a given class, you can just ask the guice injector inside a test:</p> <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">hello</span> <span class="k">=</span> <span class="nv">app</span><span class="o">.</span><span class="py">injector</span><span class="o">.</span><span class="py">instanceOf</span><span class="o">(</span><span class="n">classOf</span><span class="o">[</span><span class="kt">Hello</span><span class="o">])</span> </code></pre></div></div> </div> <hr /> <div class="footer"> If you liked this post you may want to follow me on <a href="http://twitter.com/pollmeier">Twitter</a> and subscribe to the <a href="/feed.xml">RSS feed</a>. </div> </article> </div> </div> <script src="/assets/js/jquery.min.js"></script> <script src="/assets/js/jquery.mobilemenu.min.js"></script> <script> $(document).ready(function(){ $('#sidebar nav ul').mobileMenu({'topOptionText': 'Menu', 'prependTo': '#sidebar nav'}); }); </script> </body> </html>