diff --git a/friday.cabal b/friday.cabal
--- a/friday.cabal
+++ b/friday.cabal
@@ -2,7 +2,7 @@
 --                      +-+------- breaking API changes
 --                      | | +----- non-breaking API additions
 --                      | | | +--- code changes with no API change
-version:                0.2.1.1
+version:                0.2.1.2
 synopsis:               A functional image processing library for Haskell.
 homepage:               https://github.com/RaphaelJ/friday
 license:                LGPL-3
@@ -86,6 +86,8 @@
     type:       exitcode-stdio-1.0
 
     main-is:            Test.hs
+    other-modules:      Test.Vision.Histogram
+                        Test.Vision.Image
     ghc-options:        -Wall -O2 -rtsopts
     hs-source-dirs:     test/
     default-language:   Haskell2010
diff --git a/test/Test/Vision/Histogram.hs b/test/Test/Vision/Histogram.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/Vision/Histogram.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE BangPatterns
+           , CPP
+           , FlexibleContexts
+           , FlexibleInstances
+           , UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Test.Vision.Histogram (tests) where
+
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative ((<$>))
+#endif
+
+import Data.Int
+import qualified Data.Vector.Storable as V
+import Test.Framework (Test)
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck (Arbitrary (..), Positive, getPositive)
+
+import Vision.Histogram
+import Vision.Image (Grey)
+import qualified Vision.Image as I
+import Vision.Primitive (Z (..), (:.) (..), DIM1, ix1, ix3)
+import Test.Vision.Image ()
+
+instance (Arbitrary (Positive p), Bounded p, Integral p, V.Storable p)
+    => Arbitrary (Histogram DIM1 p) where
+    arbitrary = do
+        let !maxVal = maxBound `quot` 256 -- Sum musn't overflow.
+        vec <- V.replicateM 256 (getPositive <$> arbitrary)
+        return $ Histogram (Z :. 256) $ V.map (`rem` maxVal) vec
+
+tests :: [Test]
+tests = [
+      testProperty "Sum of bins equals the number of pixels" propCalcHist
+
+    , testProperty "The reduction of a 2D histogram gives the linear one."
+                   propReduceHist
+
+    , testProperty "Resizing an histogram equals computing the smallest one."
+                   propResizeHist
+
+    , testProperty "Cumulative histogram last bin equals original's sum"
+                   propCumulatHist
+
+    , testProperty "Sum of an normalized histogram equals its size"
+                   propNormalizedHist
+
+    , testProperty "Comparing the same histogram returns a perfect correlation"
+                   propCorrelation
+    , testProperty "Comparing the same histogram returns a 0 chi-square value"
+                   propChiSquare
+    , testProperty
+        "The intersection of an histogram with itself is the sum of its values."
+        propIntersec
+    , testProperty "Comparing the same histogram returns a 0 EMD value"
+                   propEMD
+    ]
+
+-- | The sum of the values of the histogram is equal to the number of pixels of
+-- the image.
+propCalcHist :: Grey -> Bool
+propCalcHist img =
+    let Z :. h :. w     = I.shape img
+        Histogram _ vec = histogram Nothing img
+    in V.sum vec == w * h
+
+-- | Checks the identity @histogram == reduce . histogram2D@.
+propReduceHist :: Grey -> Bool
+propReduceHist img =
+    let hist1 = histogram Nothing img :: Histogram DIM1 Int32
+        hist2 = reduce (histogram2D (ix3 256 3 3) img)
+    in hist1 == hist2
+
+-- | Checks the resizing of an histogram equals the direct computation of the
+-- smallest one.
+propResizeHist :: Grey -> Bool
+propResizeHist img =
+    let hist1 = histogram (Just (ix1 128)) img :: Histogram DIM1 Int32
+        hist2 = resize (ix1 128) (histogram (Just (ix1 256)) img)
+    in hist1 == hist2
+
+-- | Checks if the last bin of the cumulative histogram equals the sum of the
+-- values of the original histogram.
+propCumulatHist :: Histogram DIM1 Int32 -> Bool
+propCumulatHist hist@(Histogram _ vec) =
+    let Histogram _ vec' = cumulative hist
+    in V.sum vec == vec' V.! 255
+
+-- | Checks that the sums of an equalized histogram equals the desired value.
+propNormalizedHist :: Double -> Histogram DIM1 Int32 -> Bool
+propNormalizedHist val hist =
+    let Histogram _ vec = normalize val hist
+    in round (V.sum vec) == (round val :: Integer)
+
+-- | Checks that the comparison of two identical histograms gives the
+-- correlation value 1.
+propCorrelation :: Histogram DIM1 Int32 -> Bool
+propCorrelation hist = round (compareCorrel hist hist :: Double) == (1 :: Int)
+
+-- | Checks that the comparison of two identical histograms gives the zero
+-- Chi-square value.
+propChiSquare :: Histogram DIM1 Int32 -> Bool
+propChiSquare hist = round (compareChi hist hist :: Double) == (0 :: Int)
+
+-- | Checks that the comparison of two identical histograms gives the sum of the
+-- values of the histogram.
+propIntersec :: Histogram DIM1 Int32 -> Bool
+propIntersec hist@(Histogram _ vec) = compareIntersect hist hist == V.sum vec
+
+-- | Checks that the comparison of two identical histograms gives a zero
+-- EMD value.
+propEMD :: Histogram DIM1 Int32 -> Bool
+propEMD hist = compareEMD hist hist == 0
diff --git a/test/Test/Vision/Image.hs b/test/Test/Vision/Image.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/Vision/Image.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE CPP
+           , FlexibleContexts
+           , FlexibleInstances
+           , TypeFamilies
+           , UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Test.Vision.Image (tests) where
+
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative ((<*>), (<$>))
+#endif
+
+import Data.Vector.Storable (Storable, replicateM)
+import Test.Framework (Test, testGroup)
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck (Arbitrary (..), choose)
+
+import Vision.Image (
+      MaskedImage (..), Image (..), Interpolable, FromFunction (..)
+    , ImageChannel, Manifest (..), Delayed (..)
+    , Grey, GreyPixel (..), HSVPixel
+    , RGBA, RGBAPixel (..), RGBADelayed
+    , RGB, RGBPixel (..), InterpolMethod (..)
+    , convert, resize, horizontalFlip, verticalFlip
+    )
+import Vision.Primitive (Z (..), (:.) (..), Size)
+
+maxImageSize :: Int
+maxImageSize = 100
+
+instance (Arbitrary p, Storable p) => Arbitrary (Manifest p) where
+    arbitrary = do
+        w <- choose (1, maxImageSize)
+        h <- choose (1, maxImageSize)
+        vec  <- replicateM (w * h) arbitrary
+        return $ Manifest (Z :. h :. w) vec
+
+instance Arbitrary GreyPixel where
+    arbitrary = GreyPixel <$> arbitrary
+
+instance Arbitrary RGBAPixel where
+    arbitrary = RGBAPixel <$> arbitrary <*> arbitrary <*> arbitrary
+                          <*> arbitrary
+
+instance Arbitrary RGBPixel where
+    arbitrary = RGBPixel <$> arbitrary <*> arbitrary <*> arbitrary
+
+tests :: [Test]
+tests = [
+      testGroup "Conversions identities" [
+          testProperty "RGB to/from RGBA" $ propRGBRGBA
+        , testProperty "RGB to/from HSV"  $ propRGBHSV
+        ]
+    , testGroup "Nearest-neighbor resize" [
+          testProperty "Grey" (propImageResize :: Grey -> Bool)
+        , testProperty "RGBA" (propImageResize :: RGBA -> Bool)
+        , testProperty "RGB"  (propImageResize :: RGB  -> Bool)
+        ]
+    , testGroup "Horizontal flip is symetric" [
+          testProperty "Grey" (propHorizontalFlip :: Grey -> Bool)
+        , testProperty "RGBA" (propHorizontalFlip :: RGBA -> Bool)
+        , testProperty "RGB"  (propHorizontalFlip :: RGB  -> Bool)
+        ]
+    , testGroup "Vertical flip is symetric" [
+          testProperty "Grey" (propVerticalFlip :: Grey -> Bool)
+        , testProperty "RGBA" (propVerticalFlip :: RGBA -> Bool)
+        , testProperty "RGB"  (propVerticalFlip :: RGB  -> Bool)
+        ]
+    ]
+
+-- | Tests if the conversions between RGB and RGBA images give the same images.
+propRGBRGBA :: RGB -> Bool
+propRGBRGBA img =
+    let img' = convert (convert img :: RGBADelayed) :: RGB
+    in img == img'
+
+-- | Tests if the conversions between RGB and HSV images give the same images.
+propRGBHSV :: RGBPixel -> Bool
+propRGBHSV pix =
+    same pix pix'
+  where
+    pix' = convert (convert pix :: HSVPixel) :: RGBPixel
+
+    err = 9
+
+    same (RGBPixel r g b) (RGBPixel r' g' b') =
+        abs (r - r') + abs (g - g') + abs (b - b') <= err
+
+-- | Tests if by increasing the size of the image by a factor of two and then
+-- reducing by a factor of two give the original image.
+propImageResize :: (Image i, FromFunction i, FromFunctionPixel i ~ ImagePixel i
+                   , Interpolable (ImagePixel i), Integral (ImageChannel i)
+                   , Eq i)
+                => i -> Bool
+propImageResize img =
+    img == resize' size (resize' (Z :. (h * 2) :. (w * 2)) img)
+  where
+    size@(Z :. h :. w) = shape img
+
+    resize' :: (Image i, FromFunction i, FromFunctionPixel i ~ ImagePixel i
+               , Interpolable (ImagePixel i), Integral (ImageChannel i))
+            => Size -> i -> i
+    resize' size' = resize NearestNeighbor size'
+
+-- | Tests if applying the horizontal flip twice gives the original image.
+propHorizontalFlip :: (Image i, FromFunction i
+                      , FromFunctionPixel i ~ ImagePixel i, Eq i) => i -> Bool
+propHorizontalFlip img =
+    img == horizontalFlip (delayedFlip img)
+  where
+    delayedFlip :: (Image i, ImagePixel i ~ p) => i -> Delayed p
+    delayedFlip = horizontalFlip
+
+-- | Tests if applying the vertical flip twice gives the original image.
+propVerticalFlip :: (Image i, FromFunction i
+                      , FromFunctionPixel i ~ ImagePixel i, Eq i) => i -> Bool
+propVerticalFlip img =
+    img == verticalFlip (delayedFlip img)
+  where
+    delayedFlip :: (Image i, ImagePixel i ~ p) => i -> Delayed p
+    delayedFlip = verticalFlip
