diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,7 @@
+# 1.0.4
+
+* We now use the `classname` attribute to indicate the test group a test came from. Thanks to @haishengwu-okta for this feature.
+
 # 1.0.3
 
 * Now creates the directory containing the report XML file. Thanks to @haishengwu-okta for this feature.
diff --git a/Test/Tasty/Runners/AntXML.hs b/Test/Tasty/Runners/AntXML.hs
--- a/Test/Tasty/Runners/AntXML.hs
+++ b/Test/Tasty/Runners/AntXML.hs
@@ -12,7 +12,7 @@
 import Numeric (showFFloat)
 import Control.Applicative
 import Control.Arrow (first)
-import Control.Monad.Trans.Class (lift)
+import Control.Monad.IO.Class (liftIO)
 import Data.Maybe (fromMaybe)
 import Data.Monoid (Monoid(..), Endo(..), Sum(..))
 import Data.Proxy (Proxy(..))
@@ -25,8 +25,11 @@
 
 import qualified Control.Concurrent.STM as STM
 import qualified Control.Monad.State as State
+import qualified Control.Monad.Reader as Reader
 import qualified Data.Functor.Compose as Functor
 import qualified Data.IntMap as IntMap
+import qualified Test.Tasty as Tasty
+import qualified Test.Tasty.Providers as Tasty
 import qualified Test.Tasty.Options as Tasty
 import qualified Test.Tasty.Runners as Tasty
 import qualified Text.XML.Light as XML
@@ -75,10 +78,16 @@
         timeDigits = 3
         showTime time = showFFloat (Just timeDigits) time ""
 
+        runTest :: (Tasty.IsTest t)
+                => Tasty.OptionSet
+                -> Tasty.TestName
+                -> t
+                -> Tasty.Traversal (Functor.Compose (Reader.ReaderT [String] (State.StateT IntMap.Key IO)) (Const Summary))
         runTest _ testName _ = Tasty.Traversal $ Functor.Compose $ do
           i <- State.get
+          groupNames <- Reader.ask
 
-          summary <- lift $ STM.atomically $ do
+          summary <- liftIO $ STM.atomically $ do
             status <- STM.readTVar $
               fromMaybe (error "Attempted to lookup test by index outside bounds") $
                 IntMap.lookup i statusMap
@@ -86,6 +95,7 @@
             let testCaseAttributes time = map (uncurry XML.Attr . first XML.unqual)
                   [ ("name", testName)
                   , ("time", showTime time)
+                  , ("classname", unwords groupNames)
                   ]
 
                 mkSummary contents =
@@ -120,7 +130,8 @@
           Const summary <$ State.modify (+ 1)
 
         runGroup groupName children = Tasty.Traversal $ Functor.Compose $ do
-          Const soFar <- Functor.getCompose $ Tasty.getTraversal children
+          Const soFar <- Reader.withReaderT (++ [groupName]) $ Functor.getCompose $ Tasty.getTraversal children
+
           let grouped = appEndo (xmlRenderer soFar) $
                 XML.node (XML.unqual "testsuite") $
                   XML.Attr (XML.unqual "name") groupName
@@ -131,7 +142,7 @@
 
       in do
         (Const summary, tests) <-
-          flip State.runStateT 0 $ Functor.getCompose $ Tasty.getTraversal $
+          flip State.runStateT 0 $ flip Reader.runReaderT [] $ Functor.getCompose $ Tasty.getTraversal $
            Tasty.foldTestTree
              Tasty.trivialFold { Tasty.foldSingle = runTest, Tasty.foldGroup = runGroup }
              options
diff --git a/tasty-ant-xml.cabal b/tasty-ant-xml.cabal
--- a/tasty-ant-xml.cabal
+++ b/tasty-ant-xml.cabal
@@ -1,5 +1,5 @@
 name: tasty-ant-xml
-version: 1.0.3
+version: 1.0.4
 synopsis: Render tasty output to XML for Jenkins
 description: A tasty ingredient to output test results in XML, using the Ant schema. This XML can be consumed by the Jenkins continuous integration framework.
 homepage: http://github.com/ocharles/tasty-ant-xml
