diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for hspec-need-env
+
+## 0.1.0.0  -- 2018-07-18
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2018, Toshio Ito
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Toshio Ito nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# hspec-need-env
+
+A simple tool to read environment variables for hspec tests.
+
+See [Test.Hspec.NeedEnv](https://hackage.haskell.org/package/hspec-need-env/docs/Test-Hspec-NeedEnv.html) for detail.
+
+
+## Author
+
+Toshio Ito <debug.ito@gmail.com>
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/hspec-need-env.cabal b/hspec-need-env.cabal
new file mode 100644
--- /dev/null
+++ b/hspec-need-env.cabal
@@ -0,0 +1,55 @@
+name:                   hspec-need-env
+version:                0.1.0.0
+author:                 Toshio Ito <debug.ito@gmail.com>
+maintainer:             Toshio Ito <debug.ito@gmail.com>
+license:                BSD3
+license-file:           LICENSE
+synopsis:               Read environment variables for hspec tests
+description:            Read environment variables for hspec tests. See 'Test.Hspec.NeedEnv'.
+category:               Test
+cabal-version:          >= 1.10
+build-type:             Simple
+extra-source-files:     README.md, ChangeLog.md
+homepage:               https://github.com/debug-ito/hspec-need-env
+bug-reports:            https://github.com/debug-ito/hspec-need-env/issues
+
+library
+  default-language:     Haskell2010
+  hs-source-dirs:       src
+  ghc-options:          -Wall -fno-warn-unused-imports
+  -- default-extensions:   
+  -- other-extensions:     
+  exposed-modules:      Test.Hspec.NeedEnv
+  -- other-modules:        
+  build-depends:        base >=4.6.0.0 && <4.12,
+                        hspec-expectations >=0.7.2 && <0.9,
+                        hspec-core >=2.2.4 && <2.6
+
+-- executable hspec-need-env
+--   default-language:     Haskell2010
+--   hs-source-dirs:       app
+--   main-is:              Main.hs
+--   ghc-options:          -Wall -fno-warn-unused-imports
+--   -- other-modules:        
+--   -- default-extensions:   
+--   -- other-extensions:     
+--   build-depends:        base
+
+test-suite spec
+  type:                 exitcode-stdio-1.0
+  default-language:     Haskell2010
+  hs-source-dirs:       test
+  ghc-options:          -Wall -fno-warn-unused-imports "-with-rtsopts=-M512m"
+  main-is:              Spec.hs
+  -- default-extensions:   
+  other-extensions:     CPP
+  other-modules:        Test.Hspec.NeedEnvSpec,
+                        Synopsis
+  build-depends:        base, hspec-need-env, hspec-core,
+                        hspec >=2.2.4,
+                        setenv >=0.1.1.3 && <0.2,
+                        transformers >=0.5.2.0 && <0.6
+
+source-repository head
+  type:                 git
+  location:             https://github.com/debug-ito/hspec-need-env.git
diff --git a/src/Test/Hspec/NeedEnv.hs b/src/Test/Hspec/NeedEnv.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Hspec/NeedEnv.hs
@@ -0,0 +1,118 @@
+-- |
+-- Module: Test.Hspec.NeedEnv
+-- Description: Read environment variables for hspec tests
+-- Maintainer: Toshio Ito <debug.ito@gmail.com>
+-- 
+-- <https://github.com/debug-ito/hspec-need-env/tree/master/test/Synopsis.hs Synopsis>:
+--
+-- > module Synopsis (main,spec) where
+-- > 
+-- > import Control.Applicative ((<$>), (<*>))
+-- > import Test.Hspec (Spec, SpecWith, hspec, before, describe, it, shouldBe)
+-- > import Test.Hspec.NeedEnv (EnvMode(Need), needEnv, needEnvRead)
+-- > 
+-- > main :: IO ()
+-- > main = hspec spec
+-- > 
+-- > -- | Read environment variables for parameters necessary for testing.
+-- > getEnvs :: IO (String, Int)
+-- > getEnvs = (,)
+-- >           <$> needEnv mode "TEST_USER_NAME"
+-- >           <*> needEnvRead mode "TEST_SEED"
+-- >   where
+-- >     mode = Need
+-- > 
+-- > spec :: Spec
+-- > spec = before getEnvs $ specWithUserAndSeed
+-- >        -- ^ Use 'before' and similar functions to write 'SpecWith'
+-- >        -- that takes parameters.
+-- > 
+-- > -- | Test spec that depends on the environment variables.
+-- > specWithUserAndSeed :: SpecWith (String, Int)
+-- > specWithUserAndSeed = describe "funcUnderTest" $ do
+-- >   it "should do something" $ \(user_name, seed) -> do
+-- >     funcUnderTest user_name seed `shouldBe` "SOMETHING"
+-- > 
+-- > funcUnderTest :: String -> Int -> String
+-- > funcUnderTest = undefined
+--
+-- This module exports 'needEnv' and other similar functions that read
+-- environment variables in hspec tests. They are useful to write
+-- tests that depend on some external entities, e.g. Web servers,
+-- database servers and random number generators.
+module Test.Hspec.NeedEnv
+       ( -- * Basics
+         EnvMode(..),
+         needEnv,
+         needEnvParse,
+         needEnvRead,
+         -- * Utilities
+         needEnvHostPort
+       ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Data.Monoid ((<>))
+import System.Environment (lookupEnv)
+import Test.Hspec.Core.Spec (pendingWith)
+import Test.Hspec.Expectations (expectationFailure)
+import Text.Read (readEither)
+
+-- | How to treat missing environment variable.
+data EnvMode = Need
+               -- ^ If the environment variable is not set, the test
+               -- fails.
+             | Want
+               -- ^ If the environment variable is not set, the test
+               -- gets pending.
+             deriving (Show,Eq,Ord,Enum,Bounded)
+
+-- | Get value of the specified environment variable. If the
+-- environment variable is not set, it executes the action specified
+-- by the 'EnvMode'.
+needEnv :: EnvMode
+        -> String -- ^ name of the environment variable
+        -> IO String -- ^ value of the environment variable
+needEnv mode envkey = do
+  mval <- lookupEnv envkey
+  case mval of
+   Nothing -> do
+     signalMsg ("Environment variable " <> envkey <> " is not set.")
+     return ""
+   Just str -> return str
+  where
+    signalMsg = case mode of
+      Need -> expectationFailure
+      Want -> pendingWith
+
+-- | Get environment variable by 'needEnv', and parse the value. If it
+-- fails to parse, the test fails.
+needEnvParse :: EnvMode
+             -> (String -> Either String a) -- ^ the parser of the environment variable
+             -> String
+             -> IO a
+needEnvParse mode parseEnvVal envkey = do
+  val_str <- needEnv mode envkey
+  case parseEnvVal val_str of
+   Right val -> return val
+   Left e -> do
+     let error_msg = "Fail to parse environment variable " <> envkey <> ": " <> e
+     expectationFailure error_msg
+     error error_msg
+
+-- | Parse the environment variable with 'Read' class.
+needEnvRead :: (Read a)
+            => EnvMode -> String -> IO a
+needEnvRead mode = needEnvParse mode readEither
+
+-- | Get the pair of hostname and port number from environment
+-- variables.
+--
+-- It reads environment variables @(prefix ++ \"_HOST\")@ and
+-- @(prefix ++ \"_PORT\")@.
+needEnvHostPort :: EnvMode
+                -> String -- ^ prefix of environment variables
+                -> IO (String,Int)
+needEnvHostPort mode prefix = (,) <$> needStr "_HOST" <*> needInt "_PORT"
+  where
+    needStr suffix = needEnv mode (prefix ++ suffix)
+    needInt suffix = needEnvRead mode (prefix ++ suffix)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/Synopsis.hs b/test/Synopsis.hs
new file mode 100644
--- /dev/null
+++ b/test/Synopsis.hs
@@ -0,0 +1,30 @@
+module Synopsis (main,spec) where
+
+import Control.Applicative ((<$>), (<*>))
+import Test.Hspec (Spec, SpecWith, hspec, before, describe, it, shouldBe)
+import Test.Hspec.NeedEnv (EnvMode(Need), needEnv, needEnvRead)
+
+main :: IO ()
+main = hspec spec
+
+-- | Read environment variables for parameters necessary for testing.
+getEnvs :: IO (String, Int)
+getEnvs = (,)
+          <$> needEnv mode "TEST_USER_NAME"
+          <*> needEnvRead mode "TEST_SEED"
+  where
+    mode = Need
+
+spec :: Spec
+spec = before getEnvs $ specWithUserAndSeed
+       -- ^ Use 'before' and similar functions to write 'SpecWith'
+       -- that takes parameters.
+
+-- | Test spec that depends on the environment variables.
+specWithUserAndSeed :: SpecWith (String, Int)
+specWithUserAndSeed = describe "funcUnderTest" $ do
+  it "should do something" $ \(user_name, seed) -> do
+    funcUnderTest user_name seed `shouldBe` "SOMETHING"
+
+funcUnderTest :: String -> Int -> String
+funcUnderTest = undefined
diff --git a/test/Test/Hspec/NeedEnvSpec.hs b/test/Test/Hspec/NeedEnvSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/Hspec/NeedEnvSpec.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE CPP #-}
+module Test.Hspec.NeedEnvSpec (main, spec) where
+
+import Control.Monad.IO.Class (liftIO)
+import Data.List (isInfixOf)
+import Data.IORef (IORef, newIORef, modifyIORef, readIORef)
+import System.SetEnv (setEnv, unsetEnv)
+import Test.Hspec
+import Test.Hspec.Core.Runner (hspecWithResult, Summary(..), Config(..), defaultConfig)
+import Test.Hspec.Core.Formatters (Formatter)
+import qualified Test.Hspec.Core.Formatters as F
+import Test.Hspec.Core.Util (Path)
+
+import Test.Hspec.NeedEnv
+  ( EnvMode(..), needEnv, needEnvRead, needEnvHostPort
+  )
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  describe "needEnv Need" $ do
+    it "should get the specified env" $ do
+      setEnv "HOGE" "hoge"
+      successCase (needEnv Need) "HOGE" "hoge"
+    it "should fail when the specified env is not present" $ do
+      unsetEnv "HOGE"
+      failCase (needEnv Need) "HOGE" (\msg -> "not set" `isInfixOf` msg)
+  describe "needEnvRead Need" $ do
+    it "should get and parse the specified env" $ do
+      setEnv "FOOBAR" "100"
+      successCase (needEnvRead Need) "FOOBAR" (100 :: Int)
+    it "should fail when it fails to parse" $ do
+      let needEnvInt :: String -> IO Int
+          needEnvInt = needEnvRead Need
+      setEnv "FOOBAR" "hoge"
+      failCase needEnvInt "FOOBAR" (\msg -> "parse" `isInfixOf` msg)
+  describe "needEnv Want" $ do
+    it "should get the specified env" $ do
+      setEnv "FOOBAR" "foo_bar"
+      successCase (needEnv Want) "FOOBAR" "foo_bar"
+    it "should make the test pending when the specified env is not present" $ do
+      unsetEnv "FOOBAR"
+      pendingCase (needEnv Want) "FOOBAR" (\msg -> "not set" `isInfixOf` msg)
+  describe "needEnvRead Want" $ do
+    it "should fail (even if it's Want) when it fails to parse the env" $ do
+      let needEnvInt :: String -> IO Int
+          needEnvInt = needEnvRead Want
+      setEnv "FOOBAR" "hoge"
+      failCase needEnvInt "FOOBAR" (\msg -> "parse" `isInfixOf` msg)
+  describe "needEnvHostPort Need" $ do
+    it "should get host and port from environment variables the common name prefix" $ do
+      (conf, ref_results) <- configForTest
+      setEnv "PREFIX_HOGE_HOST" "192.168.17.223"
+      setEnv "PREFIX_HOGE_PORT" "1123"
+      got_summary <- hspecWithResult conf $ before (needEnvHostPort Need "PREFIX_HOGE") $ do
+        specify "dummny" $ \(host, port) -> do
+          host `shouldBe` "192.168.17.223"
+          port `shouldBe` 1123
+      got <- readIORef ref_results
+      map resultBody got `shouldBe` [ExampleSuccess]
+      got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = 0 }
+
+successCase :: (Read a, Show a, Eq a) => (String -> IO a) -> String -> a -> IO ()
+successCase envGet envkey envval = do
+  (conf, ref_results) <- configForTest
+  got_summary <- hspecWithResult conf (before (envGet envkey) $ sampleSpec envval)
+  got <- readIORef ref_results
+  map resultBody got `shouldBe` [ExampleSuccess]
+  got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = 0 }
+
+failOrPendingCase :: (ExampleResultBody -> Maybe String) -> (String -> IO a) -> String -> (String -> Bool) -> Int -> IO ()
+failOrPendingCase extractMsg envGet envkey andExpect exp_sum_failures = do
+  let expect [body] = case extractMsg body of
+        Nothing -> False
+        Just msg -> (envkey `isInfixOf` msg) && andExpect msg
+      expect _ = False
+  (conf, ref_results) <- configForTest
+  got_summary <- hspecWithResult conf (before (envGet envkey) sampleSuccess)
+  got <- fmap (map resultBody) $ readIORef ref_results
+  got `shouldSatisfy` expect
+  got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = exp_sum_failures }
+
+
+failCase :: (String -> IO a) -> String -> (String -> Bool) -> IO ()
+failCase envGet envkey andExpect = failOrPendingCase extract envGet envkey andExpect 1
+  where
+    extract (ExampleFailure mmsg) = mmsg
+    extract _ = Nothing
+
+pendingCase :: (String -> IO a) -> String -> (String -> Bool) -> IO ()
+pendingCase envGet envkey andExpect = failOrPendingCase extract envGet envkey andExpect 0
+  where
+    extract (ExamplePending mmsg) = mmsg
+    extract _ = Nothing
+
+sampleSpec :: (Eq a, Show a) => a -> SpecWith a
+sampleSpec expected = specify "dummy" $ \got -> got `shouldBe` expected
+
+sampleSuccess :: SpecWith a
+sampleSuccess = specify "dummy" $ const (True `shouldBe` True)
+
+data ExampleResultBody = ExampleSuccess
+                       | ExampleFailure (Maybe String)
+                       | ExamplePending (Maybe String)
+                       deriving (Show,Eq,Ord)
+
+type ExampleResult = (Path, ExampleResultBody)
+
+resultBody :: ExampleResult -> ExampleResultBody
+resultBody (_, b) = b
+
+#if MIN_VERSION_hspec_core(2,4,0)
+failureReasonToString :: Either e F.FailureReason -> Maybe String
+failureReasonToString (Right (F.Reason s)) = Just s
+failureReasonToString _ = Nothing
+#else
+failureReasonToString :: Either e String -> Maybe String
+failureReasonToString (Right s) = Just s
+failureReasonToString _ = Nothing
+#endif
+
+formatterForTest :: IO (Formatter, IORef [ExampleResult])
+formatterForTest = do
+  ref_results <- newIORef []
+  let putRet r = liftIO $ modifyIORef ref_results (\rs -> rs ++ [r])
+#if MIN_VERSION_hspec_core(2,5,0)
+      f = F.silent { F.exampleSucceeded = \p _ -> putRet (p, ExampleSuccess),
+                     F.exampleFailed = \p _ fr -> putRet (p, ExampleFailure (failureReasonToString $ Right fr)),
+                     F.examplePending = \p _ ms -> putRet (p, ExamplePending ms)
+                   }
+#else
+      f = F.silent { F.exampleSucceeded = \p -> putRet (p, ExampleSuccess),
+                     F.exampleFailed = \p efr -> putRet (p, ExampleFailure (failureReasonToString efr)),
+                     F.examplePending = \p ms -> putRet (p, ExamplePending ms)
+                   }
+#endif
+  return (f, ref_results)
+
+configForTest :: IO (Config, IORef [ExampleResult])
+configForTest = do
+  (fmt, ref_results) <- formatterForTest
+  let conf = defaultConfig { -- configIgnoreConfigFile = True, -- not in hspec-core-2.3.2
+                             configDryRun = False,
+                             configFormatter = Just fmt
+                           }
+  return (conf, ref_results)
