Changing these 2 lines gets what you want. Note that it's quick and dirty and will break non-testnet, so don't use this for anything but testnet:
diff --git a/src/main.cpp b/src/main.cpp
index a9311e2..b3496a1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -780,7 +780,7 @@ int64 static GetBlockValue(int nHeight, int64 nFees)
}
static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
-static const int64 nTargetSpacing = 10 * 60;
+static const int64 nTargetSpacing = 10;
static const int64 nInterval = nTargetTimespan / nTargetSpacing;
//
@@ -1784,7 +1784,7 @@ bool LoadBlockIndex(bool fAllowNew)
if (fTestNet)
{
hashGenesisBlock = uint256("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
- bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
+ bnProofOfWorkLimit = CBigNum(~uint256(0) >> 15);
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
Here's some debug.log output with those changes. I'm generating a block every 2 seconds or so. If that's too fast, increase the ">> 15" accordingly. Each increment there doubles the time between blocks.
03/05/12 07:21:54 Flushing wallet.dat
Flushed wallet.dat 132ms
askfor block 000000935f454d1641e5 0
sending getdata: block 000000935f454d1641e5
received block 000000935f454d1641e5
SetBestChain: new best=000000935f454d1641e5 height=23 work=559980566
ProcessBlock: ACCEPTED
askfor block 00000c4d375ce8f92166 0
sending getdata: block 00000c4d375ce8f92166
received block 00000c4d375ce8f92166
SetBestChain: new best=00000c4d375ce8f92166 height=24 work=561029143
ProcessBlock: ACCEPTED
askfor block 000007e863a6d86bfb1d 0
sending getdata: block 000007e863a6d86bfb1d
received block 000007e863a6d86bfb1d
SetBestChain: new best=000007e863a6d86bfb1d height=25 work=562077720
ProcessBlock: ACCEPTED
03/05/12 07:21:59 Flushing wallet.dat