diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 ## Changes
 
+#### 1.5.0.0
+
+- Preserve actual/expected for `assertEqual` failures
+
 #### 1.4.0.0
 
 - Depend on `call-stack`
diff --git a/HUnit.cabal b/HUnit.cabal
--- a/HUnit.cabal
+++ b/HUnit.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:                   HUnit
-version:                1.4.0.0
+version:                1.5.0.0
 cabal-version:          >= 1.10
 license:                BSD3
 license-file:           LICENSE
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
 easy to create, change, and execute. The [JUnit](www.junit.org) tool
 pioneered support for test-first development in [Java](http://java.sun.com).
 HUnit is an adaptation of JUnit to Haskell, a general-purpose, purely functional
-programming language. (To learn more about Haskell, see www.haskell.org](http://www.haskell.org).
+programming language. (To learn more about Haskell, see [www.haskell.org](http://www.haskell.org)).
 
 With HUnit, as with JUnit, you can easily create tests, name them, group them into
 suites, and execute them, with the framework checking the results automatically. Test
diff --git a/src/Test/HUnit/Base.hs b/src/Test/HUnit/Base.hs
--- a/src/Test/HUnit/Base.hs
+++ b/src/Test/HUnit/Base.hs
@@ -65,23 +65,6 @@
              -> Assertion
 assertString s = unless (null s) (assertFailure s)
 
--- | Asserts that the specified actual value is equal to the expected value.
--- The output message will contain the prefix, the expected value, and the
--- actual value.
---
--- If the prefix is the empty string (i.e., @\"\"@), then the prefix is omitted
--- and only the expected and actual values are output.
-assertEqual :: (HasCallStack, Eq a, Show a)
-                              => String -- ^ The message prefix
-                              -> a      -- ^ The expected value
-                              -> a      -- ^ The actual value
-                              -> Assertion
-assertEqual preface expected actual =
-  unless (actual == expected) (assertFailure msg)
- where msg = (if null preface then "" else preface ++ "\n") ++
-             "expected: " ++ show expected ++ "\n but got: " ++ show actual
-
-
 -- Overloaded `assert` Function
 -- ----------------------------
 
diff --git a/src/Test/HUnit/Lang.hs b/src/Test/HUnit/Lang.hs
--- a/src/Test/HUnit/Lang.hs
+++ b/src/Test/HUnit/Lang.hs
@@ -5,6 +5,7 @@
 module Test.HUnit.Lang (
   Assertion,
   assertFailure,
+  assertEqual,
 
   Result (..),
   performTestCase,
@@ -12,11 +13,15 @@
 -- |
 -- /Note:/ This is not part of the public API!  It is exposed so that you can
 -- tinker with the internals of HUnit, but do not expect it to be stable!
-  HUnitFailure (..)
+  HUnitFailure (..),
+  FailureReason (..),
+  formatFailureReason
 ) where
 
 import           Control.DeepSeq
 import           Control.Exception as E
+import           Control.Monad
+import           Data.List
 import           Data.Typeable
 import           Data.CallStack
 
@@ -26,11 +31,19 @@
 -- Test cases are composed of a sequence of one or more assertions.
 type Assertion = IO ()
 
-data HUnitFailure = HUnitFailure (Maybe SrcLoc) String
+data HUnitFailure = HUnitFailure (Maybe SrcLoc) FailureReason
     deriving (Eq, Show, Typeable)
 
 instance Exception HUnitFailure
 
+data FailureReason = Reason String | ExpectedButGot (Maybe String) String String
+    deriving (Eq, Show, Typeable)
+
+location :: HasCallStack => Maybe SrcLoc
+location = case reverse callStack of
+  (_, loc) : _ -> Just loc
+  [] -> Nothing
+
 -- | Unconditionally signals that a failure has occured.  All
 -- other assertions can be expressed with the form:
 --
@@ -43,13 +56,33 @@
      HasCallStack =>
      String -- ^ A message that is displayed with the assertion failure
   -> Assertion
-assertFailure msg = msg `deepseq` E.throwIO (HUnitFailure location msg)
+assertFailure msg = msg `deepseq` E.throwIO (HUnitFailure location $ Reason msg)
+
+-- | Asserts that the specified actual value is equal to the expected value.
+-- The output message will contain the prefix, the expected value, and the
+-- actual value.
+--
+-- If the prefix is the empty string (i.e., @\"\"@), then the prefix is omitted
+-- and only the expected and actual values are output.
+assertEqual :: (HasCallStack, Eq a, Show a)
+                              => String -- ^ The message prefix
+                              -> a      -- ^ The expected value
+                              -> a      -- ^ The actual value
+                              -> Assertion
+assertEqual preface expected actual =
+  unless (actual == expected) $ do
+    (prefaceMsg `deepseq` expectedMsg `deepseq` actualMsg `deepseq` E.throwIO (HUnitFailure location $ ExpectedButGot prefaceMsg expectedMsg actualMsg))
   where
-    location :: Maybe SrcLoc
-    location = case reverse callStack of
-      (_, loc) : _ -> Just loc
-      [] -> Nothing
+    prefaceMsg
+      | null preface = Nothing
+      | otherwise = Just preface
+    expectedMsg = show expected
+    actualMsg = show actual
 
+formatFailureReason :: FailureReason -> String
+formatFailureReason (Reason reason) = reason
+formatFailureReason (ExpectedButGot preface expected actual) = intercalate "\n" . maybe id (:) preface $ ["expected: " ++ expected, " but got: " ++ actual]
+
 data Result = Success | Failure (Maybe SrcLoc) String | Error (Maybe SrcLoc) String
   deriving (Eq, Show)
 
@@ -59,7 +92,7 @@
 performTestCase action =
   (action >> return Success)
      `E.catches`
-      [E.Handler (\(HUnitFailure loc msg) -> return $ Failure loc msg),
+      [E.Handler (\(HUnitFailure loc reason) -> return $ Failure loc (formatFailureReason reason)),
 
        -- Re-throw AsyncException, otherwise execution will not terminate on
        -- SIGINT (ctrl-c).  Currently, all AsyncExceptions are being thrown
