diff --git a/data-msgpack-types.cabal b/data-msgpack-types.cabal
--- a/data-msgpack-types.cabal
+++ b/data-msgpack-types.cabal
@@ -1,5 +1,5 @@
 name:                 data-msgpack-types
-version:              0.0.1
+version:              0.0.2
 synopsis:             A Haskell implementation of MessagePack.
 homepage:             http://msgpack.org/
 license:              BSD3
@@ -50,3 +50,20 @@
     , unordered-containers
     , vector
     , void
+
+test-suite testsuite
+  type: exitcode-stdio-1.0
+  default-language: Haskell2010
+  hs-source-dirs: test
+  main-is: testsuite.hs
+  other-modules:
+      Data.MessagePack.OptionSpec
+      Data.MessagePack.ResultSpec
+  ghc-options:
+      -Wall
+      -fno-warn-unused-imports
+  build-depends:
+      base < 5
+    , QuickCheck
+    , data-msgpack-types
+    , hspec
diff --git a/src/Data/MessagePack/Types/Object.hs b/src/Data/MessagePack/Types/Object.hs
--- a/src/Data/MessagePack/Types/Object.hs
+++ b/src/Data/MessagePack/Types/Object.hs
@@ -1,23 +1,19 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
-{-# LANGUAGE LambdaCase         #-}
 {-# LANGUAGE Safe               #-}
 module Data.MessagePack.Types.Object
   ( Object (..)
   ) where
 
-import           Control.Applicative       ((<$), (<$>), (<*>), (<|>))
+import           Control.Applicative       ((<$>), (<*>))
 import           Control.DeepSeq           (NFData (..))
 import qualified Data.ByteString           as S
-import qualified Data.ByteString.Lazy      as L
 import           Data.Int                  (Int64)
 import qualified Data.Text                 as T
-import qualified Data.Text.Lazy            as LT
 import           Data.Typeable             (Typeable)
 import           Data.Word                 (Word64, Word8)
 import           GHC.Generics              (Generic)
-import           Prelude                   hiding (putStr)
 import           Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
 import qualified Test.QuickCheck.Gen       as Gen
 
diff --git a/test/Data/MessagePack/OptionSpec.hs b/test/Data/MessagePack/OptionSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/MessagePack/OptionSpec.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE Trustworthy #-}
+module Data.MessagePack.OptionSpec where
+
+import           Test.Hspec
+import           Test.QuickCheck
+
+import           Control.Applicative           (empty, pure, (<$>), (<*>),
+                                                (<|>))
+import           Control.Monad                 (mplus, mzero)
+import qualified Data.MessagePack.Types.Option as O
+
+
+newtype F = F (Int -> O.Option Int)
+
+instance Show F where
+  show = const "<function>"
+
+instance Arbitrary F where
+  arbitrary = F <$> arbitrary
+
+
+-- | Checks that 'O.Option' satisfies the laws described in the 'Monad' and
+-- 'Applicative' documentation.
+--
+-- Also see:
+-- https://wiki.haskell.org/Monad_laws
+-- https://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#t:Applicative
+spec :: Spec
+spec = do
+  describe "Monad" $ do
+    it "satisfies left identity" $
+      property $ \a (F f) ->
+        (return' a `bind'` f) `shouldBe` f a
+
+    it "satisfies right identity" $
+      property $ \m ->
+        (m `bind'` return') `shouldBe` m
+
+    it "satisfies associativity" $
+      property $ \m (F f) (F g) ->
+        ((m `bind'` f) `bind'` g) `shouldBe` (m `bind'` (\x -> f x `bind'` g))
+
+    it "supports 'fail'" $
+      fail' "nope" `shouldBe` O.None
+
+  describe "Applicative" $ do
+    it "satisfies identity" $
+      property identity
+
+    it "satisfies composition" $
+      property $ \x y w -> do
+        composition  O.None             O.None              w
+        composition  O.None            (pure (y *)        ) w
+        composition (pure (x *)      )  O.None              w
+        composition (pure (x *)      ) (pure (y *)        ) w
+
+    it "satisfies homomorphism" $
+      property $ \x -> homomorphism (x *)
+
+    it "satisfies interchange" $
+      property $ \x y -> do
+        interchange  O.None            y
+        interchange (pure (x *)      ) y
+
+  describe "Alternative" $ do
+    it "chooses the left-most success" $ do
+      O.Some "a" <|> O.Some "b" `shouldBe` O.Some "a"
+      O.Some "a" <|> O.None     `shouldBe` O.Some "a"
+      O.None     <|> O.Some "b" `shouldBe` O.Some "b"
+
+    it "chooses the right-most failure" $
+      O.None        <|> O.None        `shouldBe` (O.None :: O.Option ())
+
+    describe "empty" $
+      it "is a failure" $
+        empty <|> O.Some "a" `shouldBe` O.Some "a"
+
+  describe "MonadPlus" $ do
+    it "chooses the left-most success" $ do
+      O.Some "a" `mplus` O.Some "b" `shouldBe` O.Some "a"
+      O.Some "a" `mplus` O.None     `shouldBe` O.Some "a"
+      O.None     `mplus` O.Some "b" `shouldBe` O.Some "b"
+
+    it "chooses the right-most failure" $
+      O.None     `mplus` O.None        `shouldBe` (O.None :: O.Option ())
+
+    describe "mzero" $
+      it "is a failure" $
+        mzero `mplus` O.Some "a" `shouldBe` O.Some "a"
+
+  where
+    --
+    -- Aliases constrained to the Option monad. These also help avoid lint
+    -- warnings about using monad laws.
+    --
+
+    return' :: Int -> O.Option Int
+    return' = return
+
+    bind' :: O.Option Int -> (Int -> O.Option Int) -> O.Option Int
+    bind' = (>>=)
+
+    fail' :: String -> O.Option Int
+    fail' = fail
+
+    pure' :: a -> O.Option a
+    pure' = pure
+
+    --
+    -- Applicative laws.
+    --
+
+    identity :: O.Option Int -> Expectation
+    identity v =
+      (pure' id <*> v) `shouldBe` v
+
+    composition :: O.Option (Int -> Int) -> O.Option (Int -> Int) -> O.Option Int -> Expectation
+    composition u v w =
+      (pure' (.) <*> u <*> v <*> w) `shouldBe` (u <*> (v <*> w))
+
+    homomorphism :: (Int -> Int) -> Int -> Expectation
+    homomorphism h x =
+      (pure' h <*> pure' x) `shouldBe` pure' (h x)
+
+    interchange :: O.Option (Int -> Int) -> Int -> Expectation
+    interchange u y =
+      (u <*> pure' y) `shouldBe` (pure' ($ y) <*> u)
diff --git a/test/Data/MessagePack/ResultSpec.hs b/test/Data/MessagePack/ResultSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/MessagePack/ResultSpec.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE Trustworthy #-}
+module Data.MessagePack.ResultSpec where
+
+import           Test.Hspec
+import           Test.QuickCheck
+
+import           Control.Applicative           (empty, pure, (<$>), (<*>),
+                                                (<|>))
+import qualified Data.MessagePack.Types.Result as R
+
+
+newtype F = F (Int -> R.Result Int)
+
+instance Show F where
+  show = const "<function>"
+
+instance Arbitrary F where
+  arbitrary = F <$> arbitrary
+
+
+-- | Checks that 'R.Result' satisfies the laws described in the 'Monad' and
+-- 'Applicative' documentation.
+--
+-- Also see:
+-- https://wiki.haskell.org/Monad_laws
+-- https://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#t:Applicative
+spec :: Spec
+spec = do
+  describe "Monad" $ do
+    it "satisfies left identity" $
+      property $ \a (F f) ->
+        (return' a `bind'` f) `shouldBe` f a
+
+    it "satisfies right identity" $
+      property $ \m ->
+        (m `bind'` return') `shouldBe` m
+
+    it "satisfies associativity" $
+      property $ \m (F f) (F g) ->
+        ((m `bind'` f) `bind'` g) `shouldBe` (m `bind'` (\x -> f x `bind'` g))
+
+    it "supports 'fail'" $
+      fail' "nope" `shouldBe` R.Failure "nope"
+
+  describe "Applicative" $ do
+    it "satisfies identity" $
+      property identity
+
+    it "satisfies composition" $
+      property $ \x y w -> do
+        composition (R.Failure "nope") (R.Failure "no way") w
+        composition (R.Failure "nope") (pure (y *)        ) w
+        composition (pure (x *)      ) (R.Failure "no way") w
+        composition (pure (x *)      ) (pure (y *)        ) w
+
+    it "satisfies homomorphism" $
+      property $ \x -> homomorphism (x *)
+
+    it "satisfies interchange" $
+      property $ \x y -> do
+        interchange (R.Failure "nope") y
+        interchange (pure (x *)      ) y
+
+  describe "Alternative" $ do
+    it "chooses the left-most success" $ do
+      R.Success "a" <|> R.Success "b" `shouldBe` R.Success "a"
+      R.Success "a" <|> R.Failure "b" `shouldBe` R.Success "a"
+      R.Failure "a" <|> R.Success "b" `shouldBe` R.Success "b"
+
+    it "chooses the right-most failure" $
+      R.Failure "a" <|> R.Failure "b" `shouldBe` (R.Failure "b" :: R.Result ())
+
+    describe "empty" $
+      it "is a failure" $
+        empty <|> R.Success "a" `shouldBe` R.Success "a"
+
+  where
+    --
+    -- Aliases constrained to the Result monad. These also help avoid lint
+    -- warnings about using monad laws.
+    --
+
+    return' :: Int -> R.Result Int
+    return' = return
+
+    bind' :: R.Result Int -> (Int -> R.Result Int) -> R.Result Int
+    bind' = (>>=)
+
+    fail' :: String -> R.Result Int
+    fail' = fail
+
+    pure' :: a -> R.Result a
+    pure' = pure
+
+    --
+    -- Applicative laws.
+    --
+
+    identity :: R.Result Int -> Expectation
+    identity v =
+      (pure' id <*> v) `shouldBe` v
+
+    composition :: R.Result (Int -> Int) -> R.Result (Int -> Int) -> R.Result Int -> Expectation
+    composition u v w =
+      (pure' (.) <*> u <*> v <*> w) `shouldBe` (u <*> (v <*> w))
+
+    homomorphism :: (Int -> Int) -> Int -> Expectation
+    homomorphism h x =
+      (pure' h <*> pure' x) `shouldBe` pure' (h x)
+
+    interchange :: R.Result (Int -> Int) -> Int -> Expectation
+    interchange u y =
+      (u <*> pure' y) `shouldBe` (pure' ($ y) <*> u)
diff --git a/test/testsuite.hs b/test/testsuite.hs
new file mode 100644
--- /dev/null
+++ b/test/testsuite.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
