Setting up a test suite in HSpec - haskell

How do I specify test suites in HSpec? I'm going to have multiple *.hs test files for each of my modules and I want to just run stack test and for all of the tests to run. How do I set that up?
I tried to list the test modules like this in my cabal file but it doesn't work:
test-suite foo-test
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
, Mod1Spec.hs
build-depends: base
, containers >= 0.5.6.2
, hqfl
, hspec >= 2.2.3
, hspec >= 2.2.3
, mtl >= 2.2.1
, pipes >= 4.1.8
, random >= 1.1
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010

Here is some docs on hspec testing:
http://hspec.github.io/hspec-discover.html
If your main spec module contains just the lines:
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
hspec-discover will scan the directory tree for spec tests.
Also - here is a small hspec example:
https://github.com/hspec/hspec-example

Related

Not in scope: type constructor or class ‘Test.Framework.TestSuite’ when trying to create unit tests

I'm writing a small library in Haskell, and want to have tests to accompany it. For testing I intend to use HFT, and the project as a whole is managed by stack. stack test fails for some reason with the following output:
[1 of 2] Compiling Main ( test/Ini.hs, .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/ini-tests-tmp/Main.o ) │····························
[2 of 2] Compiling Paths_schemer ( .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs, .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/ini-tests-tm│····························
p/Paths_schemer.o ) │····························
│····························
/stuff/projects/schemer/.stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs:54:39: error: │····························
Not in scope: type constructor or class ‘Test.Framework.TestSuite’ │····························
No module named ‘Test.Framework’ is imported. │····························
│····························
/stuff/projects/schemer/.stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs:55:38: error: │····························
Not in scope: ‘Test.Framework.makeTestSuite’ │····························
No module named ‘Test.Framework’ is imported. │····························
My Ini.hs file that will later contain the tests is very bare-bone, just
import Test.Framework
main :: IO ()
main = htfMain htf_thisModulesTests
My package.yaml is
name: schemer
version: 0.1.0.0
github: "mpevnev/schemer"
license: BSD3
author: "Michail Pevnev"
maintainer: "mpevnev#gmail.com"
copyright: ""
extra-source-files: []
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/mpevnev/schemer#readme>
dependencies:
- attoparsec
- base >= 4.7 && < 5
- text
library:
source-dirs: src
tests:
ini-tests:
main: Ini.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
- -F
- -pgmF htfpp
dependencies:
- schemer
- text
- HTF
Here's the autogenerated schemer.cabal:
-- This file has been generated from package.yaml by hpack version 0.28.2.
--
-- see: https://github.com/sol/hpack
--
-- hash: 17ae623236b8f5b101f56373c975656e898efa7506acb143db7375f229509a79
name: schemer
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/mpevnev/schemer#readme>
homepage: https://github.com/mpevnev/schemer#readme
bug-reports: https://github.com/mpevnev/schemer/issues
author: Michail Pevnev
maintainer: mpevnev#gmail.com
license: BSD3
license-file: LICENSE
build-type: Simple
cabal-version: >= 1.10
source-repository head
type: git
location: https://github.com/mpevnev/schemer
library
exposed-modules:
Control.Scheme.Ini
Control.Schemer
other-modules:
Paths_schemer
hs-source-dirs:
src
build-depends:
attoparsec
, base >=4.7 && <5
, text
default-language: Haskell2010
test-suite ini-tests
type: exitcode-stdio-1.0
main-is: Ini.hs
other-modules:
Paths_schemer
hs-source-dirs:
test
ghc-options: -threaded -rtsopts -with-rtsopts=-N -F -pgmF htfpp
build-depends:
HTF
, attoparsec
, base >=4.7 && <5
, schemer
, text
default-language: Haskell2010
I'm not sure what's wrong and what is this Paths_schemer thing. Help is appreciated.
The options -F -pgmF htfpp are switched on globally. This applies the HTF preprocessor to all the files of the test suite, including the autogenerated Paths_schemer.
The more scalable solution is to enable the preprocessor only on files that import Test.Framework, using the OPTIONS_GHC pragma in each one:
{-# OPTIONS_GHC -F -pgmF htfpp #-}
Another way is to set other-modules: [] in the test-suite section in package.yaml to avoid generating Paths_schemer, although that only solves the problem for this one module.

hspec failing to import (private) code dependency despite CPP override

Let's say I have a src file like so:
{-# LANGUAGE CPP #-}
module Alphabet (
#ifdef TEST
alphabet
#endif
) where
alphabet :: [Char]
alphabet = "abcdefghijklmnopqrstuvwxyz"
a .cabal file like so:
name: Alphabet
version: 0.1.0.0
library
build-depends: base >=4.8 && <4.9, containers >=0.5 && <0.6, split >=0.2 && <0.3
hs-source-dirs: src
Exposed-modules: Alphabet
default-language: Haskell2010
test-suite alphabet-test
ghc-options: -Wall -Werror
cpp-options: -DTEST
default-extensions: OverloadedStrings
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: tests
build-depends: Alphabet, base >= 4.8 && < 4.9, containers >= 0.5 && <0.6, split >= 0.2 && < 0.3, hspec, QuickCheck
default-language: Haskell2010
A master test file like so:
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
and a test file like:
module AphabetSpec (spec) where
import Test.Hspec
import Alphabet (alphabet)
spec :: Spec
spec = do
describe "Alphabet.alphabet" $ do
it "returns the alphabet" $ do
alphabet `shouldBe` "abcdefghijklmnopqrstuvwxyz"
now running `cabal test`:
cabal test
Preprocessing library Alphabet-0.1.0.0...
In-place registering Alphabet-0.1.0.0...
Preprocessing test suite 'alphabet-test' for Alphabet-0.1.0.0...
[1 of 1] Compiling Main ( tests/AlphabetSpec.hs, dist/build/alphabet-test/alphabet-test-tmp/AlphabetSpec.o )
tests/AlphabetSpec.hs:4:27:
Module ‘Alphabet’ does not export ‘alphabet’
Why is my CPP not working as expected? How can I fix it?
Why is my CPP not working as expected?
Two-step building. Since your tests depend on the library, it gets build first. The library doesn't have any CPP options set, therefore alphabet doesn't get exported.
When the tests get built, your library is already compiled, and alphabet doesn't get exported. It's a separation of concerns.
How can I fix it?
There are several tricks to work with "hidden" (e.g. non-exported) functions. For one, you can put them all into a .Internal module. That way, users that want to use the hidden bits can do so rather easily, but the casual user doesn't have too many tools at hand.
Another way to handle this is to drop the dependency in the test and instead add the src directory to the tests:
hs-source-dirs: tests, src
However, this also means that you have to rebuild the whole library for tests, but it will enable using CPP.
A third option is to not test alphabet, but instead the observable behaviour of exported functions that depend on it. So instead of testing alphabet, you would test filterAlpha:
filterAlpha :: String -> String
filterAlpha = filter (`elem` alphabet)
You have to test filterAlpha anyway. If there are many functions that use alphabet, it is likely that you will have some test that will notice a regression if you accidentally change it.
The problem was a simply syntax error. #ifdef is wrong, #ifndef is right

Issues running tests with cabal and HUnit in haskell ('builds-depends' failed.)

I trying to run my first haskell program using cabal and HUnit. I seem to have trouble with my .cabal as I get the error:
λ cabal test
.\haskell.cabal has been changed. Re-configuring with most recently used
options. If this fails, please run configure manually.
cabal: haskell.cabal:21: Parse of field 'build-depends' failed.
Here is the .cabal file
name: haskell
version: 0.1.0.0
synopsis: fibonacci functions
category: Testing
build-type: Simple
cabal-version: >=1.10
executable haskell
main-is: Main.hs
build-depends: base >=4.8 && <4.9
hs-source-dirs: src
default-language: Haskell2010
test-suite Tests
build-depends: Test.HUnit
hs-source-dirs: test
main-is: tests.hs
Type: exitcode-stdio-1.0
test file:
import Test.HUnit
test1 = TestCase (assert True)
This is the problem:
build-depends: Test.HUnit
Perhaps you wanted build-depends: hunit ?

Haskell stack not building test executable

Background
I'm building a logfile parser in Haskell. I'm using stack to build it. Running the stack build command works happily and my project compiles. Running stack test, however, produces the following error:
parser-test: executable not found
I see the the following warning above the error message but I don't know how to avoid the redirect to which it refers.
Warning: output was redirected with -o, but no output will be generated because there is no Main module.
Relevant files
I haven't written any tests yet so the test file is as it was created by stack new. My cabal file looks like this:
...
category: Executable
build-type: Simple
-- extra-source-files:
cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules: LogParser
build-depends: base >= 4.7 && < 5
, attoparsec
, bytestring
, old-locale
, time
default-language: Haskell2010
executable parser-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, attoparsec
, bytestring
, old-locale
, time
, parser
default-language: Haskell2010
test-suite parser-test
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
build-depends: base
, attoparsec
, bytestring
, hspec
, hspec-attoparsec
, old-locale
, time
, parser
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
source-repository head
type: git
...
I presume I'm missing something but I can't find where what I'm missing is documented.
Desired behaviour
I should see the Test suite not yet implemented message outlined in the stack documentation.
The content of the test/Spec.hs file from the template is:
main :: IO ()
main = putStrLn "Test suite not yet implemented"
You can see this content at commercialhaskell/stack-templates in new-template.hsfiles.
I'm not sure where the module ParserSpec where line comes from (as brought up in the Github issue), but it's not part of the template. On my system, stack new bar && cd bar && stack test succeeds.
As to the reason behind the Main module requirement: it comes from the Cabal library, and as I understand it was added due to limitations in other compilers Cabal supports. In other words, GHC could technically allow this code to compile, but Cabal does not pass in those arguments to remain compatible with other compilers.

Executable within a library and while using the same library in cabal

This is my first try at an open source project, but I still can't get the right way to set up my .cabal file.
I have have library, an executable and a (soon to come) test config.
I want to use the library and within the executable, so the both of them can be used when it gets downloaded.
I followed this guide, but I'm still struggling with the cabal-config as I only get it to work while importing everything again.
My current directory
- src/
- Main.hs
- Format/
- C.hs
- Converter.hs
- Raw.hs
- RGB565.hs
- tests/...
- dist/...
- UTFTConverter.cabal
The executable Main.hs header looks like this.
module Main where
import Format.C
import Format.Converter
The library files in Format/ look like this.
module Format.{filename} where
...
This is what the cabal file looks like.
name: UTFTConverter
...
cabal-version: >=1.10
library
exposed-modules: Format.C
, Format.Converter
, Format.Raw
, Format.RGB565
build-depends: base >=4.7 && <4.8
, filepath >=1.3 && <1.4
, directory >=1.2 && <1.3
, time >=1.4 && <1.5
, bytestring >=0.10 && <0.11
, JuicyPixels >=3.2 && <3.3
hs-source-dirs: src
...
executable UTFTConverter
main-is: Main.hs
build-depends: base >=4.7 && <4.8
, filepath >=1.3 && <1.4
, directory >=1.2 && <1.3
, time >=1.4 && <1.5
, bytestring >=0.10 && <0.11
, JuicyPixels >=3.2 && <3.3
--, UTFTConverter ==0.1 <-- this does not work
hs-source-dirs: src
...
test-suite tests:
...
Without the comment this error comes up when I cabal build.
...
cabal: At least the following dependencies are missing:
UTFTConverter ==0.1
...
It works right now, but in the tutorial the executable was using the library in the same cabal file.
executable bassbull
main-is: Main.hs
ghc-options: -rtsopts -O2
build-depends: base,
bassbull, -- <-- this is the name of the library
bytestring,
cassava
hs-source-dirs: src
default-language: Haskell2010
I know this is currently working, but I would rather use it the right way from the start. Is this the "right" way?
That's due to your library version being 0.1.0.0, not 0.1. They don't match up exactly, thus cabal doesn't recognize your library as a candidate. Instead, use 0.1.* or 0.1.0.0 depending on your version policy:
executable UTFTConverter
main-is: Main.hs
build-depends: base >=4.7 && <4.8
, filepath >=1.3 && <1.4
, directory >=1.2 && <1.3
, time >=1.4 && <1.5
, bytestring >=0.10 && <0.11
, JuicyPixels >=3.2 && <3.3
, UTFTConverter ==0.1.0.0
hs-source-dirs: src
References
Cabal User Guide, section "Build Information".

Resources