# Advice on growing and maintaining a unit test suite for a SPA?

**URL:** <https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346>\
**Category:** Learn\
**Created:** [March 18, 2019, 10:08pm UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346 "2019-03-18T22:08:57Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![chipjacks](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chipjacks/32/1853_2.png) [@chipjacks](https://discourse.elm-lang.org/u/chipjacks)\
**Post date:** [March 18, 2019, 10:08pm UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/1 "2019-03-18T22:08:57Z")

</div>

Looking for advice on writing and maintaining a good unit test suite. I’ve been following the guidance given in [Life of a File](https://youtu.be/XpDsk374LDE) on how to grow my codebase, but that leaves me wondering how best to approach unit tests in a disciplined manner. I’ve tried just writing them to exercise the code I’ve already written (so like development driven testing), but I often find that it’s hard to maintain them with all the big refactors that seem so common.

To be more specific, here are a few pain points I’ve noticed:

- I find it really hard to pull out good data structures that will stay stable enough to build modules and tests around.
- The compiler is already checking so much that my tests often feel redundant or unnecessary.
- The Elm runtime does something that I can’t stub or mock. E.g. [https://github.com/elm-explorations/test/issues/24](https://github.com/elm-explorations/test/issues/24)
- The little helper functions that are easy to test aren’t exposed by my modules, so my tests can’t access them.

For now I’ve just been focusing on keeping my integration tests up to date using Cypress, and not worrying so much about unit tests but I miss having the feedback loop you get from a good unit test suite.

Has anyone had success growing a unit test suite alongside their codebase? How did you make it worth the extra time and effort? Any tips or examples I could look at? Thanks!

---

<div class="post-metadata">

**Author:** ![brian-watkins](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/brian-watkins/32/3014_2.png) [@brian-watkins](https://discourse.elm-lang.org/u/brian-watkins)\
**Post date:** [March 26, 2019, 11:33am UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/2 "2019-03-26T11:33:16Z")

</div>

I experienced similar pain points around testing when I first started with Elm a few years ago. In particular, I found it hard to write tests that gave me freedom to refactor (I found myself just unit testing each particular function), and I had trouble describing the behavior of my software at a high level due to difficulties around opaque types used by various libraries, including `Cmd` and `Sub` values.

I ended up writing my own testing tool called [Elmer](https://github.com/brian-watkins/elmer) which works with elm-test. It was fun to do and ended up teaching me a lot about testing; I’ve used it on some personal projects, and my colleagues have used it at work. Give it a try! (Buyer beware, though, it’s a personal project and I can’t guarantee I’ll maintain it indefinitely)

Here’s an example of a simple game I developed while practicing TDD with Elmer. You could check out its test suite: [https://github.com/brian-watkins/mindmaster](https://github.com/brian-watkins/mindmaster)

Also, Elmer itself was developed using TDD and has an extensive test suite you could check out. It saved me from breaking some behavior with a new feature just the other day!

I’m a big fan of TDD so I’d be excited to see the Elm community embrace more tools that enable this style of development.

---

<div class="post-metadata">

**Author:** ![razze](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/razze/32/1650_2.png) [@razze](https://discourse.elm-lang.org/u/razze)\
**Post date:** [March 27, 2019, 10:19am UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/3 "2019-03-27T10:19:23Z")

</div>

Can you please add your tool to [https://github.com/isRuslan/awesome-elm](https://github.com/isRuslan/awesome-elm) might be helpful some day 🙂

---

<div class="post-metadata">

**Author:** ![chipjacks](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chipjacks/32/1853_2.png) [@chipjacks](https://discourse.elm-lang.org/u/chipjacks)\
**Post date:** [March 27, 2019, 4:06pm UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/4 "2019-03-27T16:06:27Z")

</div>

Nice! That looks like just what I was looking for. Will give it a shot! 👍

Also, adding it to awesome-elm sounds like a good idea because I don’t know if I would have ever found it on my own.

---

<div class="post-metadata">

**Author:** ![Chadtech](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chadtech/32/609_2.png) [@Chadtech](https://discourse.elm-lang.org/u/Chadtech)\
**Post date:** [March 27, 2019, 10:44pm UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/5 "2019-03-27T22:44:07Z")

</div>

> [@chipjacks](#):
>
> The little helper functions that are easy to test aren’t exposed by my modules, so my tests can’t access them.

Im not 100% sure its a good idea over all, but I have effectively organized my projects, so that the tests are _inside_ the module they are meant to test.

```auto
module Data.Size exposing (Size, tests)

type alias Size = { width : Int, height : Int }

-- Helpers here

-- TESTS --

tests : Test
tests =

```

I tried this out explicitly to avoid having to expose internal helper functions like you also want to avoid.

Then to make it all work, there needs to be a main test file that imports all your project modules, just like your `Main.elm` file would.

> [@chipjacks](#):
>
> The Elm runtime does something that I can’t stub or mock.

There are straightforward workarounds to not being able to test `Cmd`s or `Browser.Key`s.

For `Cmd`s, I’ve made an `Effect` type, and returned `( Model, Effect )` from my `update` functions and then a `effectToCmd : Effect -> Cmd Msg` function to apply as a final step outside the `update` function. I know its a just work around, but I feel like this approach came with a lot of unexpected extra nice-ness.

For `Browser.Navigation.Key` Ive had good luck with what @andys8 recommended in that thread. You can just make your own key type like…

```elm
module Navigation.Key exposing (Key(..), pushUrl)

import Browser.Navigation as Nav

type Key
    = Key Nav.Key
    | TestKey

pushUrl : Key -> String -> Cmd msg
pushUrl key url =
    case key of
        Key navKey ->
            Nav.pushUrl navKey url

        TestKey ->
            Cmd.none

```

Then in your test, use the `TestKey` to build whatever data you need to make.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [April 6, 2019, 10:44pm UTC](https://discourse.elm-lang.org/t/advice-on-growing-and-maintaining-a-unit-test-suite-for-a-spa/3346/6 "2019-04-06T22:44:13Z")

</div>

Closed on April 6, 2019, 10:44pm UTC

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
