User Tools

Site Tools


codesnippets:testingconventions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
codesnippets:testingconventions [2022/04/06 13:08] f2b216codesnippets:testingconventions [2025/10/08 00:48] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Testing conventions ====== ====== Testing conventions ======
-~~DISCUSSION~~ 
  
 ===== Setup with stack ===== ===== Setup with stack =====
Line 108: Line 107:
  
 === HUnit test === === HUnit test ===
 +
 +  * Function: HUnit.testCase
 +    - parameter :: [Char]/String/TestName: The test name, ends with "#", "u" for unit test and a consecutive number. Optionally the start with a name to be distinct from other sections.
 +      * e.g. "Law A #u1", "Law A #u2", ... "Law A #u33"
 +    - parameter :: Assertation: Two functions have to have the same result left and right from operator "@?=".
 +      * e.g. 3 * 2 @?= 2 * 3
  
   * example ''spec<Module>.hs'':<code>   * example ''spec<Module>.hs'':<code>
Line 118: Line 123:
         [         [
             -- ...,             -- ...,
-            HU.testCase "#1" (A.f4 3 HU.@?= (A.f5 3 * A.f5 3)),  +            HU.testCase "#u1" (A.f4 3 HU.@?= (A.f5 3 * A.f5 3)),  
-            HU.testCase "#2" (A.f4 4 HU.@?= (A.f5 4 * A.f5 4)) -- ...+            HU.testCase "#u2" (A.f4 4 HU.@?= (A.f5 4 * A.f5 4)) -- ...
         ]         ]
  
Line 126: Line 131:
  
 === QuickCheck test === === QuickCheck test ===
 +
 +  * Function: HUnit.testProperty
 +    - parameter :: [Char]/String/TestName: The test name, ends with "#", "p" for property test and a consecutive number. Optionally the start with a name to be distinct from other sections.
 +      * e.g. "Type 1 #p1", "Type 1 #p2", ... "Type 1 #p42"
 +    - parameter :: a: Two functions from a lambda parameter left and rigth from "==>". Whereas the left on is the precondition to evaluate the rigth on, which should be an invariant beeing true.
 +      * e.g. 3 * 2 @?= 2 * 3
  
   * example ''spec<Module>.hs'':<code>   * example ''spec<Module>.hs'':<code>
Line 136: Line 147:
         [         [
             -- ...,             -- ...,
-            QC.testProperty "#1" (\nj -> A.f3 nj QC.==> (A.f4 nj == (A.f5 nj * A.f5 nj)) ), +            QC.testProperty "#p1" (\nj -> A.f3 nj QC.==> (A.f4 nj == (A.f5 nj * A.f5 nj)) ), 
-            QC.testProperty "#1" (\nj -> not A.f3 nj QC.==> (A.f4 nj == -1 ) -- ...+            QC.testProperty "#p2" (\nj -> not A.f3 nj QC.==> (A.f4 nj == -1 ) -- ...
         ]         ]
  
Line 149: Line 160:
 === Control of test samples === === Control of test samples ===
  
-QuickCheck tests with random samples, and the frequency distribution of the ramdom samples can be controlled by the class Arbitrary.+QuickCheck tests with test data of random samples, and the frequency distribution of the ramdom samples can be controlled by the class Arbitrary.
  
   * Example: Let suppose there is a type that is to huge to test all possible combinations.   * Example: Let suppose there is a type that is to huge to test all possible combinations.
  
-    * example with type declaration: <code>+    * type declaration of example: <code>
 data TooHugeToTestAll = ToHuge { ra :: Int, rb :: Int, rc :: Int, rd :: Int } data TooHugeToTestAll = ToHuge { ra :: Int, rb :: Int, rc :: Int, rd :: Int }
     deriving (Show)     deriving (Show)
 </code> </code>
  
-  * And you want to have more tests in a certain range of values plus some in the vast possibilities+  * If you want to have more tests in a certain range of values plus some in the vast possibilities then you create an orphan instance of 'Arbitrary'.
-  * Then you create an orphan instance of Arbitrary.+
  
-    * example with class instance: <code>+    * class instance of example: <code>
 instance QC.Arbitrary TooHugeToTestAll where instance QC.Arbitrary TooHugeToTestAll where
     arbitrary = ToHuge <$> f <*> f <*> f <*> f     arbitrary = ToHuge <$> f <*> f <*> f <*> f
Line 178: Line 188:
             niMin :: Int             niMin :: Int
             niMin = - niMax             niMin = - niMax
 +</code>
 +
 +=== Control of test samples for known types ===
 +
 +Background: The following instances already exist with a standard distribution for sample data.
 +
 +  * Arbitrary Bool  
 +  * Arbitrary Char  
 +  * Arbitrary Double  
 +  * Arbitrary Float  
 +  * Arbitrary Int  
 +  * Arbitrary Int8  
 +  * Arbitrary Int16  
 +  * Arbitrary Int32  
 +  * Arbitrary Int64  
 +  * Arbitrary Integer  
 +  * Arbitrary Ordering  
 +  * Arbitrary Word  
 +  * Arbitrary Word8  
 +  * Arbitrary Word16  
 +  * Arbitrary Word32  
 +  * Arbitrary Word64  
 +  * Arbitrary ()
 +  * and much more ... see all of them here [[https://hackage.haskell.org/package/tasty-quickcheck-0.10.2/docs/Test-Tasty-QuickCheck.html#t:Arbitrary|Test.Tasty - class Arbitrary]]
 +
 +Problem: So, how to control them differently?
 +
 +Solution: By declaration of a new type (by 'newtype').
 +
 +  * example: <code>
 +newtype Char' = Char' Char
 +    deriving Show
 +
 +fromChar' :: Char' -> Char
 +fromChar' (Char' ch) = ch
 +
 +instance QC.Arbitrary Char' where
 +    arbitrary =
 +        do
 +            genChar <- QC.frequency
 +                [
 +                    (1, QC.elements ['A'..'Z']),
 +                    (1, QC.elements ['a'..'z']),
 +                    (1, QC.elements ['0'..'9']),
 +                    (5, QC.chooseAny )
 +                ]
 +            return (Char' genChar)
 +
 +    -- ...
 +
 +        QC.testProperty "Char #p1" (\ch' -> (fromChar' (ch' :: Char') == '\0') QC.==> (fXYZ (fromChar' ch')) ),
 +</code>
 +
 +  * example, with a more generalised approach: <code>
 +{-# LANGUAGE FlexibleInstances #-}
 +
 +-- ...
 +
 +newtype T' a = T' a
 +    deriving Show
 +
 +fromT' :: T' a -> a
 +fromT' (T' x) = x
 +
 +instance QC.Arbitrary (T' Char) where
 +    arbitrary =
 +        do
 +            genChar <- QC.frequency
 +                [
 +                    (1, QC.elements ['A'..'Z']),
 +                    (1, QC.elements ['a'..'z']),
 +                    (1, QC.elements ['0'..'9']),
 +                    (5, QC.chooseAny )
 +                ]
 +            return (T' genChar)
 +
 +    -- ...
 +
 +            QC.testProperty "Char #p1" (\cd' -> (fromT' (cd' :: (TH.T' Char)) == '\0') QC.==> (fXYZ (fromT' cd') == '\0') ),
 </code> </code>
  
Line 208: Line 297:
     * the complete set of possible test values/data is used in unit tests,      * the complete set of possible test values/data is used in unit tests, 
     * or values for all possible equivalence classes are used      * or values for all possible equivalence classes are used 
-    * or ramdom sample values/data from complete set of possible values/data is used in case of high-volume cases (QuickCheck)+    * or random sample values/data from complete set of possible values/data is used in case of high-volume cases (QuickCheck)
   * independence:   * independence:
-    * test method is independent from library functions that are under test,  +    * test methods are independent functions within the same library,  
-    * or dependent on tested functions +    * unless they depend on independent tested functions (if dependencies are not cyclic) 
-  * boundaries+  * edge cases
-    * corner cases and boundaries are tested by unit tests (HUnit)+    * edge cases are tested by unit tests (HUnit)
   * conform doc.:   * conform doc.:
     * all tests are conform to documentation, e.g. source code comments by haddock)     * all tests are conform to documentation, e.g. source code comments by haddock)
  
-After checking the abovementioned criteria, the result is documented as source code comment:+After checking the above mentioned criteria, the result is documented as source code comment:
   * <code>   * <code>
-{-  f1 +{-  * validated: ✅
-    * validated: ✅+
         * completeness:         * completeness:
         * independence:         * independence:
-        * boundaries  : ✅+        * edge cases  : ✅
         * conform doc.: ✅ -}         * conform doc.: ✅ -}
 tgUnitf1 :: T.TestTree tgUnitf1 :: T.TestTree
Line 257: Line 345:
 After checking the abovementioned criteria, the result is documented as source code comment: After checking the abovementioned criteria, the result is documented as source code comment:
   * <code>   * <code>
-{-  class A +{-  * validated: ✅
-    * validated: ✅+
         * documented: ✅         * documented: ✅
           * laws             : ✅           * laws             : ✅
Line 292: Line 379:
 Description : provides a class for ... Description : provides a class for ...
 Copyright   : (c) <Author>, <Year> Copyright   : (c) <Author>, <Year>
-License     : <Licese>+License     : <License>
 Maintainer  : <E-Mail-Address> Maintainer  : <E-Mail-Address>
 Stability   : experimental Stability   : experimental
Line 305: Line 392:
  
   * example: <code>   * example: <code>
-{- module A +{-  * validated: ✅
-    * validated: ✅+
         * documented: ✅         * documented: ✅
         * completeness: ✅ -}         * completeness: ✅ -}
Line 321: Line 407:
 </code> </code>
  
 +
 +===== ✎ =====
 +~~DISCUSSION~~
codesnippets/testingconventions.1649243305.txt.gz · Last modified: (external edit)

Except where otherwise noted, content on this wiki is licensed under the following license: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki