
On Fri, Jun 30, 2006 at 02:52:54PM -0700, Ashley Yakeley wrote:
I'm currently considering possible unit tests, since right now I rely solely on code inspection. One possibility would be to simply time the function to show that it didn't have time to do anything really long at least. But that's not very satisfactory, since that is strictly a performance test, not a functionality test. It's like any other Haskell function: I want to implement it as efficiently as possible, but I don't guarantee any particular performance.
Ideally I would have tests like these:
* Verify noop does nothing with the file system.
* Verify noop does no networking activity.
* Verify noop makes no use of stdin/stdout/stderr.
* Verify noop does not modify any external IORefs.
etc.
I think the best approach for this kind of verification would be to break the IO monad up into classes, and then write a polymorphic function, as this would allow you to verify that your noop function behaves as expected, class Monad m => FileWriteMonad m where writeFile :: FilePath -> String -> m () ... class Monad m => FileReadMonad m where readFile :: FilePath -> m String openFileRead :: FilePath -> M Handle -- would be more general with AT ... class Monad m => NetworkMonad m where withSocketsDo :: m a -> m a ... class Monad m => RefMonad m where -- note, this could be more general with AT newIORef :: a -> m (IORef a) And then we could catch bugs in the noop function simply by looking at its type. e.g. when we saw noop :: FileReadMonad m => m () we'd have a strong suspicion that noop is actually trying to read from the filesystem, but if the type is just noop :: m () we'd have a high degree of confidence (assuming no unsafePerformIO is going on) that noop is bug-free. Unfortunately, even this isn't sufficient to show that noop will never return bottom... -- David Roundy