diff --git a/hspec-core.cabal b/hspec-core.cabal
--- a/hspec-core.cabal
+++ b/hspec-core.cabal
@@ -1,5 +1,9 @@
+-- This file has been generated from package.yaml by hpack version 0.4.0.
+--
+-- see: https://github.com/sol/hpack
+
 name:             hspec-core
-version:          2.1.7
+version:          2.1.8
 license:          MIT
 license-file:     LICENSE
 copyright:        (c) 2011-2015 Simon Hengel,
@@ -13,8 +17,7 @@
 bug-reports:      https://github.com/hspec/hspec/issues
 homepage:         http://hspec.github.io/
 synopsis:         A Testing Framework for Haskell
-description:      This package exposes internal types and functions that can be
-                  used to extend Hspec's functionality.
+description:      This package exposes internal types and functions that can be used to extend Hspec's functionality.
 
 source-repository head
   type: git
@@ -54,7 +57,7 @@
     , HUnit >= 1.2.5
     , QuickCheck >= 2.5.1
     , quickcheck-io
-    , hspec-expectations
+    , hspec-expectations == 0.7.0.*
     , async >= 2
   ghc-options: -Wall
   default-language: Haskell2010
@@ -77,6 +80,23 @@
       Test.Hspec.FailureReportSpec
       Test.Hspec.OptionsSpec
       Test.Hspec.TimerSpec
+      Test.Hspec.Compat
+      Test.Hspec.Config
+      Test.Hspec.Core.Example
+      Test.Hspec.Core.Formatters.Internal
+      Test.Hspec.Core.Formatters
+      Test.Hspec.Core.Hooks
+      Test.Hspec.Core.QuickCheck
+      Test.Hspec.Core.QuickCheckUtil
+      Test.Hspec.Core.Runner.Eval
+      Test.Hspec.Core.Runner
+      Test.Hspec.Core.Spec.Monad
+      Test.Hspec.Core.Spec
+      Test.Hspec.Core.Tree
+      Test.Hspec.Core.Util
+      Test.Hspec.FailureReport
+      Test.Hspec.Options
+      Test.Hspec.Timer
   build-depends:
       base >= 4.3 && < 5
     , random
@@ -89,7 +109,7 @@
     , HUnit >= 1.2.5
     , QuickCheck >= 2.5.1
     , quickcheck-io
-    , hspec-expectations
+    , hspec-expectations == 0.7.0.*
     , async >= 2
 
     , hspec-meta >= 2.1.5
diff --git a/src/Test/Hspec/Core/Hooks.hs b/src/Test/Hspec/Core/Hooks.hs
--- a/src/Test/Hspec/Core/Hooks.hs
+++ b/src/Test/Hspec/Core/Hooks.hs
@@ -35,15 +35,13 @@
 beforeAll :: IO a -> SpecWith a -> Spec
 beforeAll action spec = do
   mvar <- runIO (newMVar Nothing)
-  let action_ = memoize mvar action
-  before action_ spec
+  before (memoize mvar action) spec
 
 -- | Run a custom action before the first spec item.
 beforeAll_ :: IO () -> SpecWith a -> SpecWith a
 beforeAll_ action spec = do
   mvar <- runIO (newMVar Nothing)
-  let action_ = memoize mvar action
-  before_ action_ spec
+  before_ (memoize mvar action) spec
 
 memoize :: MVar (Maybe a) -> IO a -> IO a
 memoize mvar action = modifyMVar mvar $ \ma -> case ma of
diff --git a/test/Helper.hs b/test/Helper.hs
--- a/test/Helper.hs
+++ b/test/Helper.hs
@@ -14,9 +14,6 @@
 , ignoreUserInterrupt
 , throwException
 
-, shouldStartWith
-, shouldEndWith
-
 , shouldUseArgs
 ) where
 
@@ -52,12 +49,6 @@
 
 captureLines :: IO a -> IO [String]
 captureLines = fmap lines . capture_
-
-shouldStartWith :: (Eq a, Show a) => [a] -> [a] -> Expectation
-x `shouldStartWith` y = x `shouldSatisfy` isPrefixOf y
-
-shouldEndWith :: (Eq a, Show a) => [a] -> [a] -> Expectation
-x `shouldEndWith` y = x `shouldSatisfy` isSuffixOf y
 
 -- replace times in summary with zeroes
 normalizeSummary :: [String] -> [String]
diff --git a/test/Test/Hspec/Core/HooksSpec.hs b/test/Test/Hspec/Core/HooksSpec.hs
--- a/test/Test/Hspec/Core/HooksSpec.hs
+++ b/test/Test/Hspec/Core/HooksSpec.hs
@@ -11,127 +11,192 @@
 main :: IO ()
 main = hspec spec
 
+runSilent :: H.Spec -> IO ()
+runSilent = silence . H.hspec
+
+mkAppend :: IO (String -> IO (), IO [String])
+mkAppend = do
+  ref <- newIORef ([] :: [String])
+  let rec n = modifyIORef ref (++ [n])
+  return (rec, readIORef ref)
+
 spec :: Spec
 spec = do
   describe "before" $ do
     it "runs an action before every spec item" $ do
-      ref <- newIORef ([] :: [String])
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.before (append "before") $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.before (rec "before" >> return "value") $ do
+        H.it "foo" $ \value -> do
+          rec (value ++ " foo")
+        H.it "bar" $ \value -> do
+          rec (value ++ " bar")
+      retrieve `shouldReturn` ["before", "value foo", "before", "value bar"]
+
+    context "when used multiple times" $ do
+      it "is evaluated outside in" $ do
+        pending
+
+    context "when used with a QuickCheck property" $ do
+      it "runs action before every check of the property" $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.before (rec "before" >> return "value") $ do
+          H.it "foo" $ \value -> property $ rec value
+        retrieve `shouldReturn` (take 200 . cycle) ["before", "value"]
+
+      context "when used multiple times" $ do
+        it "is evaluated outside in" $ do
+          pending
+
+  describe "before_" $ do
+    it "runs an action before every spec item" $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.before_ (rec "before") $ do
         H.it "foo" $ do
-          append "foo"
+          rec "foo"
         H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
-          "before"
-        , "foo"
-        , "before"
-        , "bar"
-        ]
+          rec "bar"
+      retrieve `shouldReturn` ["before", "foo", "before", "bar"]
 
     context "when used multiple times" $ do
       it "is evaluated outside in" $ do
-        ref <- newIORef ([] :: [String])
-        let append n = modifyIORef ref (++ return n)
-        silence $ H.hspec $ H.before (append "before outer") $  H.before (append "before inner") $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do
           H.it "foo" $ do
-            append "foo"
-        readIORef ref `shouldReturn` [
-            "before outer"
-          , "before inner"
-          , "foo"
-          ]
-
-    context "when used with an action that returns a value" $ do
-      it "passes that value to the spec item" $ do
-        property $ \n -> do
-          silence $ H.hspec $ H.before (return n) $ do
-            H.it "foo" $ \m -> do
-              m `shouldBe` (n :: Int)
+            rec "foo"
+        retrieve `shouldReturn` ["outer", "inner", "foo"]
 
     context "when used with a QuickCheck property" $ do
       it "runs action before every check of the property" $ do
-        ref <- newIORef ([] :: [String])
-        let append n = modifyIORef ref (++ return n)
-        silence $ H.hspec $ H.before (append "before") $ do
-          H.it "foo" $ property $ append "foo"
-        readIORef ref `shouldReturn` (take 200 . cycle) ["before", "foo"]
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.before_ (rec "before") $ do
+          H.it "foo" $ property $ rec "foo"
+        retrieve `shouldReturn` (take 200 . cycle) ["before", "foo"]
 
+      context "when used multiple times" $ do
+        it "is evaluated outside in" $ do
+          (rec, retrieve) <- mkAppend
+          runSilent $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do
+            H.it "foo" $ property $ rec "foo"
+          retrieve `shouldReturn` (take 300 . cycle) ["outer", "inner", "foo"]
+
   describe "beforeWith" $ do
-    it "runs an action before every spec item" $ do
+    it "transforms spec argument" $ do
+      (rec, retrieve) <- mkAppend
       let action :: Int -> IO String
-          action n = return (show n)
-      property $ \n -> do
-        silence $ H.hspec $ H.before (return n) $ H.beforeWith action $ do
-          H.it "foo" $ (`shouldBe` show n)
+          action = return . show
+      runSilent $ H.before (return 23) $ H.beforeWith action $ do
+        H.it "foo" $ \value -> rec value
+      retrieve `shouldReturn` ["23"]
 
+    it "can be used multiple times" $ do
+      let action1 :: Int -> IO Int
+          action1 = return . succ
+
+          action2 :: Int -> IO String
+          action2 = return . show
+
+          action3 :: String -> IO String
+          action3 = return . ("foo " ++)
+
+      (rec, retrieve) <- mkAppend
+
+      runSilent $ H.before (return 23) $ H.beforeWith action1 $ H.beforeWith action2 $ H.beforeWith action3 $ do
+        H.it "foo" $ \value -> rec value
+
+      retrieve `shouldReturn` ["foo 24"]
+
   describe "beforeAll" $ do
     it "runs an action before the first spec item" $ do
-      ref <- newIORef []
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.beforeAll (append "beforeAll") $ do
-        H.it "foo" $ do
-          append "foo"
-        H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.beforeAll (rec "beforeAll" >> return "value") $ do
+        H.it "foo" $ \value -> do
+          rec $ "foo " ++ value
+        H.it "bar" $ \value -> do
+          rec $ "bar " ++ value
+      retrieve `shouldReturn` [
           "beforeAll"
-        , "foo"
-        , "bar"
+        , "foo value"
+        , "bar value"
         ]
 
+    context "when used with an empty list of examples" $ do
+      it "does not run specified action" $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.beforeAll (rec "beforeAll" >> return "value") $ do
+          return ()
+        retrieve `shouldReturn` []
+
+    context "when used multiple times" $ do
+      it "is evaluated outside in" $ do
+        pending
+
   describe "beforeAll_" $ do
     it "runs an action before the first spec item" $ do
-      ref <- newIORef []
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.beforeAll (append "beforeAll_") $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.beforeAll_ (rec "beforeAll_") $ do
         H.it "foo" $ do
-          append "foo"
+          rec "foo"
         H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
+          rec "bar"
+      retrieve `shouldReturn` [
           "beforeAll_"
         , "foo"
         , "bar"
         ]
 
-    context "when used with an empty list of examples" $ do
-      it "does not run specified action" $ do
-        ref <- newIORef []
-        let append n = modifyIORef ref (++ return n)
-        silence $ H.hspec $ H.beforeAll (append "beforeAll") $ do
-          return ()
-        readIORef ref `shouldReturn` []
-
-    context "when used with an action that returns a value" $ do
-      it "passes that value to the spec item" $ do
-        property $ \n -> do
-          silence $ H.hspec $ H.beforeAll (return n) $ do
-            H.it "foo" $ \m -> do
-              m `shouldBe` (n :: Int)
+    context "when used multiple times" $ do
+      it "is evaluated outside in" $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.beforeAll_ (rec "outer") $ H.beforeAll_ (rec "inner") $ do
+          H.it "foo" $ do
+            rec "foo"
+          H.it "bar" $ do
+            rec "bar"
+        retrieve `shouldReturn` [
+            "outer"
+          , "inner"
+          , "foo"
+          , "bar"
+          ]
 
   describe "after" $ do
-    it "must be used with a before action" $ do
-      ref <- newIORef ([] :: [String])
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.before (return "from before") $ H.after append $ do
+    it "runs an action after every spec item" $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.before (rec "before" >> return "from before") $ H.after rec $ do
         H.it "foo" $ \_ -> do
-          append "foo"
-      readIORef ref `shouldReturn` [
-          "foo"
+          rec "foo"
+        H.it "bar" $ \_ -> do
+          rec "bar"
+      retrieve `shouldReturn` [
+          "before"
+        , "foo"
         , "from before"
+        , "before"
+        , "bar"
+        , "from before"
         ]
 
+    it "guarantees that action is run" $ do
+      (rec, retrieve) <- mkAppend
+      silence . ignoreExitCode . H.hspec $ H.before (rec "before" >> return "from before") $ H.after rec $ do
+        H.it "foo" $ \_ -> do
+          ioError $ userError "foo" :: IO ()
+          rec "foo"
+      retrieve `shouldReturn` ["before", "from before"]
+
+    context "when used multiple times" $ do
+      it "is evaluated inside out" $ do
+        pending
+
   describe "after_" $ do
     it "runs an action after every spec item" $ do
-      ref <- newIORef ([] :: [String])
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.after_ (append "after") $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.after_ (rec "after") $ do
         H.it "foo" $ do
-          append "foo"
+          rec "foo"
         H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
+          rec "bar"
+      retrieve `shouldReturn` [
           "foo"
         , "after"
         , "bar"
@@ -139,49 +204,90 @@
         ]
 
     it "guarantees that action is run" $ do
-      ref <- newIORef ([] :: [String])
-      let append n = modifyIORef ref (++ return n)
-      silence . ignoreExitCode $ H.hspec $ H.after_ (append "after") $ do
+      (rec, retrieve) <- mkAppend
+      silence . ignoreExitCode $ H.hspec $ H.after_ (rec "after") $ do
         H.it "foo" $ do
           ioError $ userError "foo" :: IO ()
-          append "foo"
-      readIORef ref `shouldReturn` ["after"]
+          rec "foo"
+      retrieve `shouldReturn` ["after"]
 
     context "when used multiple times" $ do
       it "is evaluated inside out" $ do
-        ref <- newIORef ([] :: [String])
-        let append n = modifyIORef ref (++ return n)
-        silence $ H.hspec $ H.after_ (append "after outer") $  H.after_ (append "after inner") $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.after_ (rec "after outer") $ H.after_ (rec "after inner") $ do
           H.it "foo" $ do
-            append "foo"
-        readIORef ref `shouldReturn` [
+            rec "foo"
+        retrieve `shouldReturn` [
             "foo"
           , "after inner"
           , "after outer"
           ]
 
+  describe "afterAll" $ do
+    it "runs an action after the last spec item" $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.before (rec "before" >> return "from before") $ H.afterAll rec $ do
+        H.it "foo" $ \_ -> do
+          rec "foo"
+        H.it "bar" $ \_ -> do
+          rec "bar"
+      retrieve `shouldReturn` [
+          "before"
+        , "foo"
+        , "before"
+        , "bar"
+        , "before"
+        , "from before"
+        ]
+
+    context "when used with an empty list of examples" $ do
+      it "does not run specified action" $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.before (rec "before" >> return "from before") $ H.afterAll rec $ do
+          return ()
+        retrieve `shouldReturn` []
+
+    context "when action throws an exception" $ do
+      it "reports a failure" $ do
+        r <- runSpec $ H.before (return "from before") $ H.afterAll (\_ -> throwException) $ do
+          H.it "foo" $ \a -> a `shouldBe` "from before"
+        r `shouldSatisfy` any (== "afterAll-hook FAILED [1]")
+
   describe "afterAll_" $ do
     it "runs an action after the last spec item" $ do
-      ref <- newIORef []
-      let append n = modifyIORef ref (++ return n)
-      silence $ H.hspec $ H.afterAll_ (append "afterAll") $ do
+      (rec, retrieve) <- mkAppend
+      runSilent $ H.before_ (rec "before") $ H.afterAll_ (rec "afterAll_") $ do
         H.it "foo" $ do
-          append "foo"
+          rec "foo"
         H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
-          "foo"
+          rec "bar"
+      retrieve `shouldReturn` [
+          "before"
+        , "foo"
+        , "before"
         , "bar"
-        , "afterAll"
+        , "before"
+        , "afterAll_"
         ]
 
+    context "when used multiple times" $ do
+      it "is evaluated inside out" $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.afterAll_ (rec "after outer") $ H.afterAll_ (rec "after inner") $ do
+          H.it "foo" $ do
+            rec "foo"
+        retrieve `shouldReturn` [
+            "foo"
+          , "after inner"
+          , "after outer"
+          ]
+
     context "when used with an empty list of examples" $ do
       it "does not run specified action" $ do
-        ref <- newIORef []
-        let append n = modifyIORef ref (++ return n)
-        silence $ H.hspec $ H.afterAll_ (append "afterAll") $ do
+        (rec, retrieve) <- mkAppend
+        runSilent $ H.afterAll_ (rec "afterAll_") $ do
           return ()
-        readIORef ref `shouldReturn` []
+        retrieve `shouldReturn` []
 
     context "when action throws an exception" $ do
       it "reports a failure" $ do
@@ -192,22 +298,34 @@
 
   describe "around" $ do
     it "wraps every spec item with an action" $ do
-      property $ \n -> do
-        silence $ H.hspec $ H.around ($ n) $ do
-          H.it "foo" $ \m -> do
-            m `shouldBe` (n :: Int)
+      (rec, retrieve) <- mkAppend
+      let action e = rec "before" >> e "from around" >> rec "after"
+      runSilent $ H.around action $ do
+        H.it "foo" $ rec . ("foo " ++)
+        H.it "bar" $ rec . ("bar " ++)
+      retrieve `shouldReturn` [
+          "before"
+        , "foo from around"
+        , "after"
+        , "before"
+        , "bar from around"
+        , "after"
+        ]
 
+    context "when used multiple times" $ do
+      it "is evaluated outside in" $ do
+        pending
+
   describe "around_" $ do
     it "wraps every spec item with an action" $ do
-      ref <- newIORef ([] :: [String])
-      let append n = modifyIORef ref (++ return n)
-          action e = append "before" >> e >> append "after"
-      silence $ H.hspec $ H.around_ action $ do
+      (rec, retrieve) <- mkAppend
+      let action e = rec "before" >> e >> rec "after"
+      runSilent $ H.around_ action $ do
         H.it "foo" $ do
-          append "foo"
+          rec "foo"
         H.it "bar" $ do
-          append "bar"
-      readIORef ref `shouldReturn` [
+          rec "bar"
+      retrieve `shouldReturn` [
           "before"
         , "foo"
         , "after"
@@ -218,14 +336,13 @@
 
     context "when used multiple times" $ do
       it "is evaluated outside in" $ do
-        ref <- newIORef ([] :: [String])
-        let append n = modifyIORef ref (++ return n)
-            actionOuter e = append "before outer" >> e >> append "after outer"
-            actionInner e = append "before inner" >> e >> append "after inner"
-        silence $ H.hspec $ H.around_ actionOuter $ H.around_ actionInner $ do
+        (rec, retrieve) <- mkAppend
+        let actionOuter e = rec "before outer" >> e >> rec "after outer"
+            actionInner e = rec "before inner" >> e >> rec "after inner"
+        runSilent $ H.around_ actionOuter $ H.around_ actionInner $ do
           H.it "foo" $ do
-            append "foo"
-        readIORef ref `shouldReturn` [
+            rec "foo"
+        retrieve `shouldReturn` [
             "before outer"
           , "before inner"
           , "foo"
@@ -235,11 +352,12 @@
 
   describe "aroundWith" $ do
     it "wraps every spec item with an action" $ do
+      (rec, retrieve) <- mkAppend
       let action :: H.ActionWith String -> H.ActionWith Int
-          action e n = e (show n)
-      property $ \n -> do
-        silence $ H.hspec $ H.before (return n) $ H.aroundWith action $ do
-          H.it "foo" $ (`shouldBe` show n)
+          action e = e . show
+      runSilent $ H.before (return 23) $ H.aroundWith action $ do
+        H.it "foo" rec
+      retrieve `shouldReturn` ["23"]
   where
     runSpec :: H.Spec -> IO [String]
     runSpec = captureLines . H.hspecResult
