diff --git a/Data/Aeson/Types/FromJSON.hs b/Data/Aeson/Types/FromJSON.hs
--- a/Data/Aeson/Types/FromJSON.hs
+++ b/Data/Aeson/Types/FromJSON.hs
@@ -1258,9 +1258,12 @@
         _           -> Scientific.toRealFloat <$> parseScientificText t
 
 instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
-    parseJSON = withObject "Rational" $ \obj ->
-                  (%) <$> obj .: "numerator"
-                      <*> obj .: "denominator"
+    parseJSON = withObject "Rational" $ \obj -> do
+        numerator <- obj .: "numerator"
+        denominator <- obj .: "denominator"
+        if denominator == 0
+        then fail "Ratio denominator was 0"
+        else pure $ numerator % denominator
     {-# INLINE parseJSON #-}
 
 -- | /WARNING:/ Only parse fixed-precision numbers from trusted input
diff --git a/Data/Aeson/Types/Internal.hs b/Data/Aeson/Types/Internal.hs
--- a/Data/Aeson/Types/Internal.hs
+++ b/Data/Aeson/Types/Internal.hs
@@ -270,7 +270,9 @@
 -- | Success continuation.
 type Success a f r = a -> f r
 
--- | A JSON parser.
+-- | A JSON parser.  N.B. This might not fit your usual understanding of
+--  "parser".  Instead you might like to think of 'Parser' as a "parse result",
+-- i.e. a parser to which the input has already been applied.
 newtype Parser a = Parser {
       runParser :: forall f r.
                    JSONPath
diff --git a/aeson.cabal b/aeson.cabal
--- a/aeson.cabal
+++ b/aeson.cabal
@@ -1,5 +1,5 @@
 name:            aeson
-version:         1.3.1.0
+version:         1.3.1.1
 license:         BSD3
 license-file:    LICENSE
 category:        Text, Web, JSON
@@ -204,9 +204,9 @@
     scientific,
     tagged,
     template-haskell,
-    test-framework,
-    test-framework-hunit,
-    test-framework-quickcheck2,
+    tasty,
+    tasty-hunit,
+    tasty-quickcheck,
     text,
     time,
     time-locale-compat,
diff --git a/benchmarks/Compare/BufferBuilder.hs b/benchmarks/Compare/BufferBuilder.hs
--- a/benchmarks/Compare/BufferBuilder.hs
+++ b/benchmarks/Compare/BufferBuilder.hs
@@ -11,7 +11,6 @@
 
 import Data.BufferBuilder.Json
 import Data.Int (Int64)
-import Data.Monoid ((<>))
 import Twitter
 import qualified Data.BufferBuilder.Utf8 as UB
 
diff --git a/benchmarks/Compare/JsonBench.hs b/benchmarks/Compare/JsonBench.hs
--- a/benchmarks/Compare/JsonBench.hs
+++ b/benchmarks/Compare/JsonBench.hs
@@ -11,7 +11,7 @@
 module Compare.JsonBench (benchmarks) where
 
 import Prelude ()
-import Prelude.Compat
+import Prelude.Compat hiding ((<>))
 
 import Control.DeepSeq (NFData(..))
 import Criterion
diff --git a/benchmarks/Compare/JsonBuilder.hs b/benchmarks/Compare/JsonBuilder.hs
--- a/benchmarks/Compare/JsonBuilder.hs
+++ b/benchmarks/Compare/JsonBuilder.hs
@@ -6,7 +6,7 @@
 module Compare.JsonBuilder () where
 
 import Prelude ()
-import Prelude.Compat
+import Prelude.Compat hiding ((<>))
 
 import Data.Json.Builder
 import Data.Monoid ((<>))
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,9 @@
 For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md).
 
+### 1.3.1.1
+
+* Catch 0 denominators when parsing Ratio
+
 ### 1.3.1.0
 
 * Fix bug in generically derived `FromJSON` instances that are using `unwrapUnaryRecords`, thanks to Xia Li-yao
diff --git a/examples/Twitter/Manual.hs b/examples/Twitter/Manual.hs
--- a/examples/Twitter/Manual.hs
+++ b/examples/Twitter/Manual.hs
@@ -16,7 +16,6 @@
 import Prelude.Compat
 
 import Control.Applicative
-import Data.Monoid ((<>))
 import Twitter
 
 import Data.Aeson hiding (Result)
diff --git a/stack-lts6.yaml b/stack-lts6.yaml
--- a/stack-lts6.yaml
+++ b/stack-lts6.yaml
@@ -12,7 +12,6 @@
 - hashable-1.2.6.1
 - integer-logarithms-1
 - quickcheck-instances-0.3.16
-- test-framework-quickcheck2-0.3.0.4
 - th-abstraction-0.2.2.0
 flags:
 flags:
diff --git a/stack-lts7.yaml b/stack-lts7.yaml
--- a/stack-lts7.yaml
+++ b/stack-lts7.yaml
@@ -8,7 +8,6 @@
 - hashable-1.2.6.1
 - integer-logarithms-1
 - quickcheck-instances-0.3.16
-- test-framework-quickcheck2-0.3.0.4
 - th-abstraction-0.2.2.0
 flags:
   aeson:
diff --git a/stack-lts8.yaml b/stack-lts8.yaml
--- a/stack-lts8.yaml
+++ b/stack-lts8.yaml
@@ -7,7 +7,6 @@
 - base-compat-0.9.3
 - quickcheck-instances-0.3.16
 - th-abstraction-0.2.2.0
-- test-framework-quickcheck2-0.3.0.4
 flags:
   aeson:
     fast: true
diff --git a/tests/DataFamilies/Properties.hs b/tests/DataFamilies/Properties.hs
--- a/tests/DataFamilies/Properties.hs
+++ b/tests/DataFamilies/Properties.hs
@@ -9,12 +9,12 @@
 import DataFamilies.Instances ()
 import Properties hiding (tests)
 
-import Test.Framework (Test, testGroup)
-import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.QuickCheck (testProperty)
 
 --------------------------------------------------------------------------------
 
-tests :: Test
+tests :: TestTree
 tests = testGroup "data families" [
     testGroup "template-haskell" [
       testGroup "toJSON" [
diff --git a/tests/ErrorMessages.hs b/tests/ErrorMessages.hs
--- a/tests/ErrorMessages.hs
+++ b/tests/ErrorMessages.hs
@@ -13,13 +13,13 @@
 import Data.Proxy (Proxy(..))
 import Instances ()
 import Numeric.Natural (Natural)
-import Test.Framework (Test)
-import Test.Framework.Providers.HUnit (testCase)
+import Test.Tasty (TestTree)
+import Test.Tasty.HUnit (testCase)
 import Test.HUnit (Assertion, assertFailure, assertEqual)
 import qualified Data.ByteString.Lazy.Char8 as L
 import qualified Data.HashMap.Strict as HM
 
-tests :: [Test]
+tests :: [TestTree]
 tests =
     [
       testCase "Int" int
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -33,8 +33,8 @@
 import Encoders
 import Instances ()
 import Numeric.Natural (Natural)
-import Test.Framework (Test, testGroup)
-import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.QuickCheck (testProperty)
 import Test.QuickCheck (Arbitrary(..), Property, Testable, (===), (.&&.), counterexample)
 import Types
 import qualified Data.Attoparsec.Lazy as L
@@ -228,7 +228,7 @@
 --------------------------------------------------------------------------------
 
 
-tests :: Test
+tests :: TestTree
 tests = testGroup "properties" [
   testGroup "encode" [
       testProperty "encodeDouble" encodeDouble
diff --git a/tests/SerializationFormatSpec.hs b/tests/SerializationFormatSpec.hs
--- a/tests/SerializationFormatSpec.hs
+++ b/tests/SerializationFormatSpec.hs
@@ -35,8 +35,8 @@
 import Data.Word (Word8)
 import GHC.Generics (Generic)
 import Instances ()
-import Test.Framework (Test, testGroup)
-import Test.Framework.Providers.HUnit (testCase)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (testCase)
 import Test.HUnit (assertFailure, assertEqual)
 import Types (Approx(..), Compose3, Compose3', I)
 import qualified Data.ByteString.Lazy.Char8 as L
@@ -54,7 +54,7 @@
 import qualified Data.UUID.Types as UUID
 import qualified Data.Vector as Vector
 
-tests :: [Test]
+tests :: [TestTree]
 tests =
   [
     testGroup "To JSON representation" $ fmap assertJsonEncodingExample jsonEncodingExamples
@@ -246,7 +246,7 @@
 instance (FromJSON a, FromJSON b) => FromJSON (MyEither a b) where
     parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }
 
-assertJsonExample :: Example -> Test
+assertJsonExample :: Example -> TestTree
 assertJsonExample (Example name bss val) = testCase name $ do
     assertSomeEqual "encode"           bss        (encode val)
     assertSomeEqual "encode/via value" bss        (encode $ toJSON val)
@@ -255,7 +255,7 @@
 assertJsonExample (MaybeExample name bs mval) = testCase name $
     assertEqual "decode" mval (decode bs)
 
-assertJsonEncodingExample :: Example -> Test
+assertJsonEncodingExample :: Example -> TestTree
 assertJsonEncodingExample (Example name bss val) = testCase name $ do
     assertSomeEqual "encode"           bss (encode val)
     assertSomeEqual "encode/via value" bss (encode $ toJSON val)
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -3,7 +3,7 @@
 import Prelude ()
 import Prelude.Compat
 
-import Test.Framework (defaultMain)
+import Test.Tasty (defaultMain, testGroup)
 import qualified DataFamilies.Properties as DF
 import qualified Properties
 import qualified UnitTests
@@ -11,4 +11,5 @@
 main :: IO ()
 main = do
     ioTests <- UnitTests.ioTests
-    defaultMain (DF.tests : Properties.tests : UnitTests.tests : ioTests)
+    let allTests = DF.tests : Properties.tests : UnitTests.tests : ioTests
+    defaultMain (testGroup "tests" allTests)
diff --git a/tests/UnitTests.hs b/tests/UnitTests.hs
--- a/tests/UnitTests.hs
+++ b/tests/UnitTests.hs
@@ -43,8 +43,8 @@
 import Instances ()
 import System.Directory (getDirectoryContents)
 import System.FilePath ((</>), takeExtension, takeFileName)
-import Test.Framework (Test, testGroup)
-import Test.Framework.Providers.HUnit (testCase)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (testCase)
 import Test.HUnit (Assertion, assertBool, assertFailure, assertEqual)
 import Text.Printf (printf)
 import UnitTests.NullaryConstructors (nullaryConstructors)
@@ -62,7 +62,7 @@
 import Data.Aeson.Parser.UnescapeFFI ()
 import Data.Aeson.Parser.UnescapePure ()
 
-tests :: Test
+tests :: TestTree
 tests = testGroup "unit" [
     testGroup "SerializationFormatSpec" SerializationFormatSpec.tests
   , testGroup "ErrorMessages" ErrorMessages.tests
@@ -100,6 +100,7 @@
   , testGroup "SingleMaybeField" singleMaybeField
   , testCase "withEmbeddedJSON" withEmbeddedJSONTest
   , testCase "SingleFieldCon" singleFieldCon
+  , testCase "Ratio with denominator 0" ratioDenominator0
   ]
 
 roundTripCamel :: String -> Assertion
@@ -346,13 +347,13 @@
 -- Comparison between bytestring and text encoders
 ------------------------------------------------------------------------------
 
-ioTests :: IO [Test]
+ioTests :: IO [TestTree]
 ioTests = do
   enc <- encoderComparisonTests
   js <- jsonTestSuite
   return [enc, js]
 
-encoderComparisonTests :: IO Test
+encoderComparisonTests :: IO TestTree
 encoderComparisonTests = do
   encoderTests <- forM testFiles $ \file0 -> do
       let file = "benchmarks/json-data/" ++ file0
@@ -412,7 +413,7 @@
 
 -- JSONTestSuite
 
-jsonTestSuiteTest :: FilePath -> Test
+jsonTestSuiteTest :: FilePath -> TestTree
 jsonTestSuiteTest path = testCase fileName $ do
     payload <- L.readFile path
     let result = eitherDecode payload :: Either String Value
@@ -427,7 +428,7 @@
 -- Build a collection of tests based on the current contents of the
 -- JSONTestSuite test directories.
 
-jsonTestSuite :: IO Test
+jsonTestSuite :: IO TestTree
 jsonTestSuite = do
   let suitePath = "tests/JSONTestSuite"
   let suites = ["test_parsing", "test_transform"]
@@ -508,7 +509,7 @@
 newtype SingleMaybeField = SingleMaybeField { smf :: Maybe Int }
   deriving (Eq, Show, Generic)
 
-singleMaybeField :: [Test]
+singleMaybeField :: [TestTree]
 singleMaybeField = do
   (gName, gToJSON, gToEncoding, gFromJSON) <-
     [ ("generic", genericToJSON opts, genericToEncoding opts, parse (genericParseJSON opts))
@@ -545,6 +546,12 @@
 singleFieldCon :: Assertion
 singleFieldCon =
   assertEqual "fromJSON" (Right (SingleFieldCon 0)) (eitherDecode "0")
+
+ratioDenominator0 :: Assertion
+ratioDenominator0 =
+  assertEqual "Ratio with denominator 0"
+    (Left "Error in $: Ratio denominator was 0")
+    (eitherDecode "{ \"numerator\": 1, \"denominator\": 0 }" :: Either String Rational)
 
 deriveJSON defaultOptions{omitNothingFields=True} ''MyRecord
 
