diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,27 @@
+# Change Log
+All notable changes to this project will be documented in this file. This file
+follows the formatting recommendations from [Keep a
+CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic
+Versioning](http://semver.org/).
+
+## [0.3] - 2015-09-11
+### Added
+- Multiple `TestTree`s with different settings for dealing with `SmallCheck`
+  `Depth`.
+
+### Removed
+- `smallcheck` specific modules from
+  [`smallcheck-lens-0.1`](https://hackage.haskell.org/package/smallcheck-lens-0.1).
+  This package now contains `Tasty` specific modules.
+
+### Changed
+- Simplify module hierarchy: `Test.Tasty.SmallCheck.Lens` -> `Test.Tasty.Lens`
+
+## [0.1] - 2015-05-27
+### Added
+- `SmallCheck` properties for each lens laws.
+- `tasty` test trees for each `Lens` type.
+- Tests for some `Lens`.
+
+[0.3]: https://github.com/jdnavarro/tasty-lens/compare/v0.1...v0.3
+[0.1]: https://github.com/jdnavarro/tasty-lens/compare/1df060...v0.1
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, J Daniel Navarro
+
+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 J. Daniel Navarro 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,35 @@
+# Tasty Lens
+
+[![Hackage Version](https://img.shields.io/hackage/v/tasty-lens.svg)](https://hackage.haskell.org/package/tasty-lens)
+[![Build Status](https://img.shields.io/travis/jdnavarro/tasty-lens.svg)](https://travis-ci.org/jdnavarro/tasty-lens)
+
+Preassembled [`tasty`](https://hackage.haskell.org/package/tasty) `TestTree`s
+with sensible defaults for the validation of:
+
+- `Lens`
+- `Setter`
+- `Traversal`
+- `Iso`
+- `Prism`
+
+Although these tests offer weaker guarantees compared to manually proving the
+laws through equational reasoning, they can still be useful for regression
+testing where you don't want to manually proof every time you make a slight
+change that could affect the laws.
+
+It uses [`smallcheck-lens`](https://github.com/jdnavarro/smallcheck-laws)
+under the hood. If you don't find any functions to create the `TestTree`s you
+are looking for, you may want to use the `smallcheck-lens` package directly.
+In such case you can still check this package as a reference to implement your
+own `smallcheck-lens` `TestTree`s.
+
+Check the
+[tests](https://github.com/jdnavarro/tasty-lens/blob/master/tests/tasty.hs) in
+this package for usage examples.
+
+## Contact
+
+Contributions and bug reports are welcome!
+
+Please feel free to contact jdnavarro on the #haskell IRC channel on
+irc.freenode.net.
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/Test/Tasty/Lens/Iso.hs b/Test/Tasty/Lens/Iso.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Lens/Iso.hs
@@ -0,0 +1,93 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Lens.Iso as Iso
+--
+module Test.Tasty.Lens.Iso
+  (
+  -- * Tests
+    test
+  , testSeries
+  , testExhaustive
+  -- * Re-exports
+  , module Test.SmallCheck.Lens.Iso
+  ) where
+
+import Control.Lens
+import Test.SmallCheck.Series (Serial(series), CoSerial, Series)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.SmallCheck (testProperty)
+
+import Test.SmallCheck.Lens.Iso (hither, yon)
+import qualified Test.Tasty.Lens.Lens as Lens
+
+-- | An 'Iso'' is only legal if the following laws hold:
+--
+-- 1. @s ^. l . from l ≡ s@
+--
+-- 2. @s ^. from l . l ≡ s@
+--
+-- It uses the 'Serial' and 'CoSerial' instances for @s@ and @a@. If you are
+-- not creating your own orphan instances be aware of combinatorial explosion
+-- since the default implementations usually aim for exhaustivity.
+--
+-- This uses "Test.Tasty.Lens.Lens"@.@'Lens.test' to validate the 'Iso'' is
+-- a valid 'Lens'' in both normal and reverse form.
+test
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial Identity s, Serial IO s, CoSerial IO s
+     , Serial Identity a, Serial IO a, CoSerial IO a
+     )
+  => Iso' s a -> TestTree
+test l = testSeries l series series
+
+-- | An 'Iso'' is only legal if the following laws hold:
+--
+-- 1. @s ^. l . from l ≡ s@
+--
+-- 2. @s ^. from l . l ≡ s@
+--
+-- As in 'test' both @s@ and @a@ need to be 'Serial' and 'CoSerial' instances,
+-- but here you explicitly pass custom 'Series' of @s@ and @a@ for the forward
+-- case, while the reverse case still uses 'Serial' and 'CoSerial' instances.
+-- If you want to fine tune both the forward and reverse cases, you should
+-- create your own 'TestTree'.
+--
+-- This uses "Test.Tasty.Lens.Lens"@.@'Lens.testSeries', with the custom
+-- 'Series' for @s@ and @a@, to validate the 'Iso'' is a valid 'Lens'' in both
+-- normal and reverse form.
+testSeries
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial Identity s, Serial IO s, CoSerial IO s
+     , Serial Identity a, Serial IO a, CoSerial IO a
+     )
+  => Iso' s a -> Series IO s -> Series IO a -> TestTree
+testSeries l ss as = testGroup "Iso Laws"
+  [ testProperty "s ^. l . from l ≡ s" $ hither l ss
+  , testProperty "s ^. from l . l ≡ s" $ yon l as
+  , Lens.testSeries l ss
+  , Lens.testSeries (from l) as
+  ]
+
+-- | An 'Iso'' is only legal if the following laws hold:
+--
+-- 1. @s ^. l . from l ≡ s@
+--
+-- 2. @s ^. from l . l ≡ s@
+--
+-- This is the same as 'test' except it uses
+-- "Test.Tasty.Lens.Lens"@.@'Lens.testExhaustive' to validate the 'Lens'' laws.
+-- Be aware of combinatorial explosions.
+testExhaustive
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial Identity s, Serial IO s, CoSerial IO s
+     , Serial Identity a, Serial IO a, CoSerial IO a
+     )
+  => Iso' s a -> TestTree
+testExhaustive l = testGroup "Iso Laws"
+  [ testProperty "s ^. l . from l ≡ s" $ hither l series
+  , testProperty "s ^. from l . l ≡ s" $ yon l series
+  , Lens.testExhaustive l
+  , Lens.testExhaustive (from l)
+  ]
diff --git a/Test/Tasty/Lens/Lens.hs b/Test/Tasty/Lens/Lens.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Lens/Lens.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Lens.Lens as Lens
+--
+module Test.Tasty.Lens.Lens
+  (
+  -- * Tests
+    test
+  , testSeries
+  , testExhaustive
+  -- * Re-exports
+  , module Test.SmallCheck.Lens.Lens
+  ) where
+
+import Data.Proxy (Proxy(..))
+
+import Control.Lens
+import Test.SmallCheck.Series (Serial(series), CoSerial, Series)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.SmallCheck (testProperty)
+
+import Test.SmallCheck.Lens.Lens (setView, viewSet)
+import qualified Test.Tasty.Lens.Traversal as Traversal
+
+-- | A 'Lens'' is only legal if it's a valid 'Traversal'' and if the following
+--   laws hold:
+--
+-- 1. @view l (set l b a)  ≡ b@
+--
+-- 2. @set l (view l a) a  ≡ a@
+--
+-- 3. @set l c (set l b a) ≡ set l c a@
+--
+-- It uses the 'Serial' and 'CoSerial' instances for @s@ and @a@. If you are
+-- not creating your own orphan instances be aware of combinatorial explosion
+-- since the default implementations usually aim for exhaustivity.
+--
+-- This also uses "Test.Tasty.Lens.Traversal"@.@'Traversal.test', with the
+-- 'Maybe' functor, to validate the 'Lens'' is a valid 'Traversal''.
+test
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Lens' s a -> TestTree
+test l = testSeries l series
+
+-- | A 'Lens'' is only legal if it's a valid 'Traversal'' and if the following
+--   laws hold:
+--
+-- 1. @view l (set l b a)  ≡ b@
+--
+-- 2. @set l (view l a) a  ≡ a@
+--
+-- 3. @set l c (set l b a) ≡ set l c a@
+--
+-- Here you explicitly pass a custom 'Series' for @s@, while for @a@ the
+-- @Serial@ instance is used. If you want to fine tune both 'Series', you
+-- should create your own 'TestTree'.
+--
+-- This also uses "Test.Tasty.Lens.Traversal"@.@'Traversal.testSeries', with
+-- the 'Maybe' functor and the custom @s@ 'Series', to validate the 'Lens'' is
+-- a valid 'Traversal''.
+testSeries
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Lens' s a -> Series IO s -> TestTree
+testSeries l ss = testGroup "Lens Laws"
+  [ testProperty "view l (set l b a) ≡ b" $
+      setView l ss
+  , testProperty "set l (view l a) a ≡ a" $
+      viewSet l ss series
+  , Traversal.testSeries (Proxy :: Proxy Maybe) l ss
+  ]
+
+-- | A 'Lens'' is only legal if it's a valid 'Traversal'' and if the following
+-- laws hold:
+--
+-- 1. @view l (set l b a)  ≡ b@
+--
+-- 2. @set l (view l a) a  ≡ a@
+--
+-- 3. @set l c (set l b a) ≡ set l c a@
+--
+-- This is like the same as 'test' except it uses
+-- "Test.Tasty.Lens.Traversal"@.@'Traversal.testExhaustive' to validate
+-- 'Traversal'' laws. Be aware of combinatorial explosions.
+testExhaustive
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Lens' s a -> TestTree
+testExhaustive l = testGroup "Lens Laws"
+  [ testProperty "view l (set l b a) ≡ b" $
+      setView l series
+  , testProperty "set l (view l a) a ≡ a" $
+      viewSet l series series
+  , Traversal.testExhaustive (Proxy :: Proxy Maybe) l
+  ]
diff --git a/Test/Tasty/Lens/Prism.hs b/Test/Tasty/Lens/Prism.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Lens/Prism.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Lens.Prism as Prism
+--
+module Test.Tasty.Lens.Prism
+  (
+  -- * Tests
+    test
+  , testExhaustive
+  -- * Re-exports
+  , module Test.SmallCheck.Lens.Prism
+  ) where
+
+import Data.Proxy (Proxy(..))
+
+import Control.Lens
+import Test.SmallCheck.Series (Serial(series), Series, CoSerial)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.SmallCheck (testProperty)
+
+import Test.SmallCheck.Lens.Prism (yin, yang)
+import qualified Test.Tasty.Lens.Traversal as Traversal
+
+-- | A 'Prism'' is only legal if it's a valid 'Traversal'' and if the following
+--   laws hold:
+--
+-- 1. @preview l (review l b) ≡ Just b"@
+--
+-- 2. @maybe s (review l) (preview l s) ≡ s@
+--
+-- It uses the 'Serial' and 'CoSerial' instances for @s@ and @a@. If you are
+-- not creating your own orphan instances be aware of combinatorial explosion
+-- since the default implementations usually aim for exhaustivity.
+--
+-- This also uses "Test.Tasty.Lens.Traversal"@.@'Traversal.test', with the
+-- 'Maybe' functor, to validate the 'Prism'' is a valid 'Traversal''.
+test
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Prism' s a -> TestTree
+test l = testSeries l series
+
+-- | A 'Prism'' is only legal if it's a valid 'Traversal'' and if the following
+--   laws hold:
+--
+-- 1. @preview l (review l b) ≡ Just b"@
+--
+-- 2. @maybe s (review l) (preview l s) ≡ s@
+--
+-- Here you explicitly pass a custom 'Series' for @s@, while for @a@ the
+-- @Serial@ instance is used. If you want to fine tune both 'Series', you
+-- should create your own 'TestTree'.
+--
+-- This also uses "Test.Tasty.Lens.Traversal"@.@'Traversal.testSeries', with
+-- the 'Maybe' functor and the custom @s@ 'Series', to validate the 'Prism'' is
+-- a valid 'Traversal''.
+testSeries
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Prism' s a -> Series IO s -> TestTree
+testSeries l ss = testGroup "Prism Laws"
+  [ testProperty "preview l (review l b) ≡ Just b" $ yin l series
+  , testProperty "maybe s (review l) (preview l s) ≡ s" $ yang l ss
+  , Traversal.testSeries (Proxy :: Proxy Maybe) l ss
+  ]
+
+-- | A 'Prism'' is only legal if it's a valid 'Traversal'' and if the following
+--   laws hold:
+--
+-- 1. @preview l (review l b) ≡ Just b"@
+--
+-- 2. @maybe s (review l) (preview l s) ≡ s@
+--
+-- This is the same as 'test' except it uses
+-- "Test.Tasty.Lens.Traversal"@.@'Traversal.testExhaustive' to validate
+-- 'Traversal'' laws. Be aware of combinatorial explosions.
+testExhaustive
+  :: ( Eq s, Eq a, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, CoSerial IO a
+     )
+  => Prism' s a -> TestTree
+testExhaustive l = testGroup "Prism Laws"
+  [ testProperty "preview l (review l b) ≡ Just b" $ yin l series
+  , testProperty "maybe s (review l) (preview l s) ≡ s" $ yang l series
+  , Traversal.testExhaustive (Proxy :: Proxy Maybe) l
+  ]
diff --git a/Test/Tasty/Lens/Setter.hs b/Test/Tasty/Lens/Setter.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Lens/Setter.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Lens.Setter as Setter
+--
+module Test.Tasty.Lens.Setter
+  (
+  -- * Tests
+    test
+  , testSeries
+  , testExhaustive
+  -- * Re-exports
+  , module Test.SmallCheck.Lens.Setter
+  ) where
+
+import Control.Lens
+import Test.SmallCheck.Series (Serial(series), Series)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.SmallCheck (testProperty)
+
+import Test.SmallCheck.Lens.Setter
+  ( identity
+  , setSet
+  , setSetSum
+  , composition
+  , compositionSum
+  )
+
+-- | A 'Setter' is only legal if the following laws hold:
+--
+-- 1. @set l y (set l x a) ≡ set l y a@
+--
+-- 2. @over l id ≡ id@
+--
+-- 3. @over l f . over l g ≡ over l (f . g)@
+--
+-- The 'Serial' and 'CoSerial' instances for @s@ and @a@. If you are
+-- not creating your own orphan instances be aware of combinatorial explosion
+-- since the default implementations usually aim for exhaustivity.
+--
+-- In this case @f@ and @g@ are of type @a -> a@ and when combining them the
+-- /sum/ of 'Series' is used.
+test
+  :: ( Eq s, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, Serial IO (a -> a)
+     )
+  => Setter' s a -> TestTree
+test l = testSeries l series
+
+-- | A 'Setter' is only legal if the following laws hold:
+--
+-- 1. @set l y (set l x a) ≡ set l y a@
+--
+-- 2. @over l id ≡ id@
+--
+-- 3. @over l f . over l g ≡ over l (f . g)@
+--
+-- Here you explicitly pass a custom 'Series' for @s@, while for @a@ the
+-- @Serial@ instance is used. If you want to fine tune both 'Series', you
+-- should create your own 'TestTree'.
+--
+-- In this case @f@ and @g@ are of type @a -> a@ and when combining them the
+-- /sum/ of 'Series' is used.
+testSeries
+  :: ( Eq s, Show s, Show a
+     , Serial IO a, Serial Identity a, Serial IO (a -> a)
+     )
+  => Setter' s a -> Series IO s -> TestTree
+testSeries l ss = testGroup "Setter Laws"
+  [ testProperty "over l id ≡ id" $ identity l ss
+  , testProperty "set l y (set l x a) ≡ set l y a" $
+      setSetSum l ss series series
+  , testProperty "over l f . over l g ≡ over l (f . g)" $
+      compositionSum l ss series series
+  ]
+
+-- | A 'Setter' is only legal if the following laws hold:
+--
+-- 1. @set l y (set l x a) ≡ set l y a@
+--
+-- 2. @over l id ≡ id@
+--
+-- 3. @over l f . over l g ≡ over l (f . g)@
+--
+-- This is the same as 'test' except it uses the /product/ when combining the
+-- @f@ and @g@ 'Series'.
+testExhaustive
+  :: ( Eq s, Show s, Show a
+     , Serial IO s
+     , Serial IO a, Serial Identity a, Serial IO (a -> a)
+     )
+  => Setter' s a -> TestTree
+testExhaustive l = testGroup "Setter Laws"
+  [ testProperty "over l id ≡ id" $ identity l series
+  , testProperty "set l y (set l x a) ≡ set l y a" $
+      setSet l series series series
+  , testProperty "over l f . over l g ≡ over l (f . g)" $
+      composition l series series series
+  ]
diff --git a/Test/Tasty/Lens/Traversal.hs b/Test/Tasty/Lens/Traversal.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Lens/Traversal.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Lens.Traversal as Traversal
+--
+module Test.Tasty.Lens.Traversal
+  (
+  -- * Tests
+    test
+  , testSeries
+  , testExhaustive
+  -- * Re-exports
+  , module Test.SmallCheck.Lens.Traversal
+  ) where
+
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative (Applicative)
+#endif
+import Data.Proxy (Proxy(..))
+
+import Control.Lens
+import Test.SmallCheck.Series (Serial(series), CoSerial, Series)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.SmallCheck (testProperty)
+
+import qualified Test.SmallCheck.Lens.Traversal as Traversal
+import Test.SmallCheck.Lens.Traversal (composition, compositionSum)
+import qualified Test.Tasty.Lens.Setter as Setter
+
+-- | A 'Traversal'' is only legal if it is a valid 'Setter'' and if the
+--   following laws hold:
+--
+-- 1. @t pure ≡ pure@
+--
+-- 2. @fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)@
+--
+-- The 'Serial' and 'CoSerial' instances for @s@ and @a@. If you are
+-- not creating your own orphan instances be aware of combinatorial explosion
+-- since the default implementations usually aim for exhaustivity.
+--
+-- The 'Proxy' arguments lets you choose the 'Functor' to use in the tests. @f@
+-- and @g@ are of type @a -> functor a@ and when combining them the /sum/ of
+-- 'Series' is used.
+--
+-- This also uses "Test.Tasty.Lens.Setter"@.@'Setter.test' to validate the
+-- 'Traversal'' is a valid 'Setter''.
+test
+  :: forall f s a .
+     ( Applicative f 
+     , Eq s, Eq (f s), Eq (f (f s))
+     , Show s, Show a, Show (f a)
+     , Serial IO s
+     , Serial Identity a, Serial IO a, Serial IO (f a), CoSerial IO a
+     )
+  => Proxy f -> Traversal' s a -> TestTree
+test p t = testSeries p t series
+
+-- | A 'Traversal'' is only legal if it is a valid 'Setter'' and if the
+--   following laws hold:
+--
+-- 1. @t pure ≡ pure@
+--
+-- 2. @fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)@
+--
+-- Here you explicitly pass a custom 'Series' for @s@, while for @a@ the
+-- @Serial@ instance is used. If you want to fine tune both 'Series', you
+-- should create your own 'TestTree'.
+--
+-- The 'Proxy' arguments lets you choose the 'Functor' to use in the tests. @f@
+-- and @g@ are of type @a -> functor a@ and when combining them the /sum/ of
+-- 'Series' is used.
+--
+-- This also uses "Test.Tasty.Lens.Setter"@.@'Setter.test' to validate the
+-- 'Traversal'' is a valid 'Setter''.
+testSeries
+  :: forall f s a .
+     ( Applicative f 
+     , Eq s, Eq (f s), Eq (f (f s))
+     , Show s, Show a, Show (f a)
+     , Serial Identity a, Serial IO a, Serial IO (f a), CoSerial IO a
+     )
+  => Proxy f -> Traversal' s a -> Series IO s -> TestTree
+testSeries p t ss = testGroup "Traversal Laws"
+  [ testProperty "t pure ≡ pure" $ Traversal.pure p t ss
+  , testProperty "fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)" $
+       compositionSum t ss (series :: Series IO (a -> f a))
+                           (series :: Series IO (a -> f a))
+  , Setter.testSeries t ss
+  ]
+
+
+-- | A 'Traversal'' is only legal if it is a valid 'Setter'' and if the
+--   following laws hold:
+--
+-- 1. @t pure ≡ pure@
+--
+-- 2. @fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)@
+--
+-- This is the same as 'test' except it uses the /product/ when combining the
+-- @f@ and @g@ 'Series' and "Test.Tasty.Lens.Setter"@.@'Setter.testExhaustive'
+-- to validate 'Setter'' laws. Be aware of combinatorial explosions.
+testExhaustive
+  :: forall f s a .
+     ( Applicative f 
+     , Eq s, Eq (f s), Eq (f (f s))
+     , Show s, Show a, Show (f a)
+     , Serial IO s
+     , Serial Identity a, Serial IO a, Serial IO (f a), CoSerial IO a
+     )
+  => Proxy f -> Traversal' s a -> TestTree
+testExhaustive p t = testGroup "Traversal Laws"
+  [ testProperty "t pure ≡ pure" $ Traversal.pure p t series
+  , testProperty "fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)" $
+       composition t series (series :: Series IO (a -> f a))
+                            (series :: Series IO (a -> f a))
+  , Setter.testExhaustive t
+  ]
diff --git a/stack.yaml b/stack.yaml
new file mode 100644
--- /dev/null
+++ b/stack.yaml
@@ -0,0 +1,7 @@
+flags: {}
+packages:
+- '.'
+extra-deps:
+- smallcheck-lens-0.3
+- smallcheck-series-0.5.1
+resolver: lts-3.4
diff --git a/tasty-lens.cabal b/tasty-lens.cabal
new file mode 100644
--- /dev/null
+++ b/tasty-lens.cabal
@@ -0,0 +1,48 @@
+name:                tasty-lens
+version:             0.3
+synopsis:            Tasty TestTrees for Lens validation
+description:
+  Preassembled 'tasty' 'TestTree's for property testing @Lens@es, @Setter@s,
+  @Traversal@s, @Iso@s and @Prism@s laws.
+homepage:            https://github.com/jdnavarro/tasty-lens
+bug-reports:         https://github.com/jdnavarro/tasty-lens/issues
+license:             BSD3
+license-file:        LICENSE
+author:              Danny Navarro
+maintainer:          j@dannynavarro.net
+category:            Testing, Lenses
+build-type:          Simple
+extra-source-files:  README.md CHANGELOG.md stack.yaml
+cabal-version:       >=1.10
+
+source-repository head
+  type: git
+  location: git://github.com/jdnavarro/tasty-lens.git
+
+library
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+  exposed-modules:     Test.Tasty.Lens.Iso
+                       Test.Tasty.Lens.Lens
+                       Test.Tasty.Lens.Prism
+                       Test.Tasty.Lens.Setter
+                       Test.Tasty.Lens.Traversal
+  build-depends:       base >=4.6 && <4.9,
+                       lens >=4.1.2.1,
+                       smallcheck >=1.1.1,
+                       smallcheck-lens >=0.3,
+                       tasty >=0.10,
+                       tasty-smallcheck >=0.8.0.1
+  if impl(ghc < 7.8)
+     build-depends: tagged >=0.7.2
+
+test-suite tasty
+  default-language:    Haskell2010
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      tests
+  main-is:             tasty.hs
+  ghc-options:         -Wall -threaded
+  build-depends:       base >= 4.6 && <4.9,
+                       lens >=4.1.2.1,
+                       tasty >=0.10,
+                       tasty-lens
diff --git a/tests/tasty.hs b/tests/tasty.hs
new file mode 100644
--- /dev/null
+++ b/tests/tasty.hs
@@ -0,0 +1,68 @@
+module Main where
+
+import Control.Lens
+import Numeric.Lens (hex, negated, adding)
+import Test.Tasty (TestTree, defaultMain, testGroup)
+
+import qualified Test.Tasty.Lens.Iso as Iso
+import qualified Test.Tasty.Lens.Lens as Lens
+import qualified Test.Tasty.Lens.Prism as Prism
+
+main :: IO ()
+main = defaultMain $ testGroup "Lens tests"
+  [ tupleTests
+  , maybeTests
+  , numTests
+  ]
+
+tupleTests :: TestTree
+tupleTests = testGroup "Tuples"
+  [ testGroup "_1"
+    [ testGroup "Lens' (Char,Char) Char"
+      [ Lens.test (_1 :: Lens' (Char,Char) Char) ]
+    , testGroup "Lens' (Int,Char) Int"
+      [ Lens.test (_1 :: Lens' (Int,Char) Int) ]
+    ]
+  , testGroup "_2"
+     [ testGroup "Lens' (Char,Char,Char) Char"
+       [ Lens.test (_2 :: Lens' (Char,Char,Char) Char) ]
+     ]
+  ]
+
+maybeTests :: TestTree
+maybeTests = testGroup "Maybe"
+  [ testGroup "_Nothing"
+    [ testGroup "Prism' (Maybe Char) ()"
+      [ Prism.test (_Nothing :: Prism' (Maybe Char) ()) ]
+    , testGroup "Prism' (Maybe Int) ()"
+      [ Prism.test (_Nothing :: Prism' (Maybe Int) ()) ]
+    ]
+  , testGroup "_Just"
+    [ testGroup "Prism' (Maybe Char) Char"
+      [ Prism.test (_Just :: Prism' (Maybe Char) Char) ]
+    , testGroup "Prism' (Maybe Int) Int"
+      [ Prism.test (_Just :: Prism' (Maybe Int) Int) ]
+    ]
+  ]
+
+numTests :: TestTree
+numTests = testGroup "Numeric"
+  [ testGroup "negated"
+    [ testGroup "Iso' Int Int"
+      [ Iso.test (negated :: Iso' Int Int) ]
+    , testGroup "Iso' Float Float"
+      [ Iso.test (negated :: Iso' Float Float) ]
+    ]
+  , testGroup "hex"
+    [ testGroup "Prism'' String Int"
+      [ Prism.test (hex :: Prism' String Int) ]
+    , testGroup "Prism'' String Integer"
+      [ Prism.test (hex :: Prism' String Integer) ]
+    ]
+  , testGroup "adding"
+    [ testGroup "Iso' Int Int"
+      [ Iso.test (adding 2 :: Iso' Int Int) ]
+    , testGroup "Iso' Integer Integer"
+      [ Iso.test (adding 3 :: Iso' Integer Integer) ]
+    ]
+  ]
