diff --git a/Makefile.am b/Makefile.am
index efdbd07d1fc344dc28278be01d332b7329c4a6bc..5666aeb5ba3369ba77592665b429e8524f5ebc3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -446,6 +446,8 @@ HS_LIB_SRCS = \
 	htest/Test/Ganeti/HTools/Text.hs \
 	htest/Test/Ganeti/HTools/Types.hs \
 	htest/Test/Ganeti/HTools/Utils.hs \
+	htest/Test/Ganeti/JSON.hs \
+	htest/Test/Ganeti/Jobs.hs \
 	htest/Test/Ganeti/Luxi.hs \
 	htest/Test/Ganeti/Objects.hs \
 	htest/Test/Ganeti/OpCodes.hs \
diff --git a/htest/Test/Ganeti/JSON.hs b/htest/Test/Ganeti/JSON.hs
new file mode 100644
index 0000000000000000000000000000000000000000..6a42fd7bd44aa8f5bb551404e1277a1d6a95d2b4
--- /dev/null
+++ b/htest/Test/Ganeti/JSON.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+{-| Unittests for ganeti-htools.
+
+-}
+
+{-
+
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Test.Ganeti.JSON (testJSON) where
+
+import Test.QuickCheck
+
+import qualified Text.JSON as J
+
+import Test.Ganeti.TestHelper
+import Test.Ganeti.TestCommon
+
+import qualified Ganeti.BasicTypes as BasicTypes
+import qualified Ganeti.JSON as JSON
+
+prop_JSON_toArray :: [Int] -> Property
+prop_JSON_toArray intarr =
+  let arr = map J.showJSON intarr in
+  case JSON.toArray (J.JSArray arr) of
+    BasicTypes.Ok arr' -> arr ==? arr'
+    BasicTypes.Bad err -> failTest $ "Failed to parse array: " ++ err
+
+prop_JSON_toArrayFail :: Int -> String -> Bool -> Property
+prop_JSON_toArrayFail i s b =
+  -- poor man's instance Arbitrary JSValue
+  forAll (elements [J.showJSON i, J.showJSON s, J.showJSON b]) $ \item ->
+  case JSON.toArray item of
+    BasicTypes.Bad _ -> property True
+    BasicTypes.Ok result -> failTest $ "Unexpected parse, got " ++ show result
+
+testSuite "JSON"
+          [ 'prop_JSON_toArray
+          , 'prop_JSON_toArrayFail
+          ]
diff --git a/htest/Test/Ganeti/Jobs.hs b/htest/Test/Ganeti/Jobs.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f2ada1039c52148d802990beff4849f2355f9ef6
--- /dev/null
+++ b/htest/Test/Ganeti/Jobs.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+{-| Unittests for ganeti-htools.
+
+-}
+
+{-
+
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Test.Ganeti.Jobs (testJobs) where
+
+import Test.QuickCheck
+
+import qualified Text.JSON as J
+
+import Test.Ganeti.TestHelper
+import Test.Ganeti.TestCommon
+
+import qualified Ganeti.Jobs as Jobs
+
+-- * Arbitrary instances
+
+instance Arbitrary Jobs.OpStatus where
+  arbitrary = elements [minBound..maxBound]
+
+instance Arbitrary Jobs.JobStatus where
+  arbitrary = elements [minBound..maxBound]
+
+-- * Test cases
+
+-- | Check that (queued) job\/opcode status serialization is idempotent.
+prop_Jobs_OpStatus_serialization :: Jobs.OpStatus -> Property
+prop_Jobs_OpStatus_serialization os =
+  case J.readJSON (J.showJSON os) of
+    J.Error e -> failTest $ "Cannot deserialise: " ++ e
+    J.Ok os' -> os ==? os'
+
+prop_Jobs_JobStatus_serialization :: Jobs.JobStatus -> Property
+prop_Jobs_JobStatus_serialization js =
+  case J.readJSON (J.showJSON js) of
+    J.Error e -> failTest $ "Cannot deserialise: " ++ e
+    J.Ok js' -> js ==? js'
+
+testSuite "Jobs"
+            [ 'prop_Jobs_OpStatus_serialization
+            , 'prop_Jobs_JobStatus_serialization
+            ]
diff --git a/htest/test.hs b/htest/test.hs
index 7065bd2530c03569839f41f4f93bc1258a1581b3..a56db603b20b3ad5664dd3d9f3286a968435072e 100644
--- a/htest/test.hs
+++ b/htest/test.hs
@@ -29,7 +29,7 @@ import Data.Monoid (mappend)
 import Test.Framework
 import System.Environment (getArgs)
 
-import Ganeti.HTools.QC
+import Ganeti.HTools.QC ()
 import Test.Ganeti.Confd.Utils
 import Test.Ganeti.HTools.CLI
 import Test.Ganeti.HTools.Cluster
@@ -42,6 +42,8 @@ import Test.Ganeti.HTools.Simu
 import Test.Ganeti.HTools.Text
 import Test.Ganeti.HTools.Types
 import Test.Ganeti.HTools.Utils
+import Test.Ganeti.Jobs
+import Test.Ganeti.JSON
 import Test.Ganeti.Luxi
 import Test.Ganeti.Objects
 import Test.Ganeti.OpCodes
diff --git a/htools/Ganeti/HTools/QC.hs b/htools/Ganeti/HTools/QC.hs
index 8cfb1b3e5aa5ea11cdacd7e544ea3e8715558bc3..15256141c807635d54b2f504de02f2efc37a760a 100644
--- a/htools/Ganeti/HTools/QC.hs
+++ b/htools/Ganeti/HTools/QC.hs
@@ -32,9 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 -}
 
 module Ganeti.HTools.QC
-  ( testJobs
-  , testJSON
-  ) where
+  () where
 
 import qualified Test.HUnit as HUnit
 import Test.QuickCheck
@@ -100,57 +98,3 @@ import qualified Ganeti.HTools.Program.Hspace
 
 import Test.Ganeti.TestHelper (testSuite)
 import Test.Ganeti.TestCommon
-
--- * Helper functions
-
-
-instance Arbitrary Jobs.OpStatus where
-  arbitrary = elements [minBound..maxBound]
-
-instance Arbitrary Jobs.JobStatus where
-  arbitrary = elements [minBound..maxBound]
-
--- * Actual tests
-
-
--- ** Jobs tests
-
--- | Check that (queued) job\/opcode status serialization is idempotent.
-prop_Jobs_OpStatus_serialization :: Jobs.OpStatus -> Property
-prop_Jobs_OpStatus_serialization os =
-  case J.readJSON (J.showJSON os) of
-    J.Error e -> failTest $ "Cannot deserialise: " ++ e
-    J.Ok os' -> os ==? os'
-
-prop_Jobs_JobStatus_serialization :: Jobs.JobStatus -> Property
-prop_Jobs_JobStatus_serialization js =
-  case J.readJSON (J.showJSON js) of
-    J.Error e -> failTest $ "Cannot deserialise: " ++ e
-    J.Ok js' -> js ==? js'
-
-testSuite "Jobs"
-            [ 'prop_Jobs_OpStatus_serialization
-            , 'prop_Jobs_JobStatus_serialization
-            ]
-
--- * JSON tests
-
-prop_JSON_toArray :: [Int] -> Property
-prop_JSON_toArray intarr =
-  let arr = map J.showJSON intarr in
-  case JSON.toArray (J.JSArray arr) of
-    Types.Ok arr' -> arr ==? arr'
-    Types.Bad err -> failTest $ "Failed to parse array: " ++ err
-
-prop_JSON_toArrayFail :: Int -> String -> Bool -> Property
-prop_JSON_toArrayFail i s b =
-  -- poor man's instance Arbitrary JSValue
-  forAll (elements [J.showJSON i, J.showJSON s, J.showJSON b]) $ \item ->
-  case JSON.toArray item of
-    Types.Bad _ -> property True
-    Types.Ok result -> failTest $ "Unexpected parse, got " ++ show result
-
-testSuite "JSON"
-          [ 'prop_JSON_toArray
-          , 'prop_JSON_toArrayFail
-          ]