I used a general test to manage test suites, and then in the test spec you can declare a cover spec using a tuple {cover, "path to space"}:
{include, ["../include"]}. {suites,"../test", all}. {logdir,"../results"}. {cover,"../test/reduce.coverspec"}.
The cover specification basically defines the level of detail and the list of modules you want to analyze:
{level, details}. {incl_mods, [calc,calc_store]}.
then when you run the test, you get an incremental web page with the entire test iteration, which, when done, and for each result and link to the coverage summary, and then your source code, annotated with the amount of time, the line was evaluated.



and annotated source:
File generated from d:/documents and Settings/xxxxxxx/My Documents/git/calc/ebin/../src/calc_store.erl by COVER 2012-06-01 at 10:23:45 **************************************************************************** | -module(calc_store). | | -behaviour(gen_server). | | -record(state,{var,func}). | -define(SERVER,?MODULE). | | %% gen_server call back | -export([code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]). | | %% api | -export([start_link/0,storevar/2,storefunc/4,getvalue/1,getfunc/1,stop/0]). | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | | storevar(Name,Value) -> 1..| gen_server:cast(?MODULE,{storevar,Name,Value}). | | storefunc(Name,Par,Desc,Text) -> 3..| gen_server:cast(?MODULE,{storefunc,Name,Par,Desc,Text}). | | getvalue(Name) -> 67..| gen_server:call(?MODULE,{readvar,Name}). | | getfunc(Name) -> 10..| gen_server:call(?MODULE,{readfunc,Name}). | | stop() -> 0..| gen_server:cast(?MODULE,stop). | | start_link() -> 1..| gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | | init([]) -> | %% register(?MODULE,self()), 1..| {ok,#state{var=dict:new(),func=dict:new()}}. | | handle_call({readvar,Name}, _From, State = #state{var=D}) -> 67..| Reply = dict:find(Name,D), 67..| {reply, Reply, State}; | handle_call({readfunc,Name}, _From, State = #state{func=F}) -> 10..| Reply = dict:find(Name,F) , 10..| {reply, Reply, State}; | handle_call(Request, From, State) -> 0..| io:format("calc_store received call: ~p from ~p~n",[Request,From]), 0..| Reply = ok, 0..| {reply, Reply, State}. | | handle_cast(stop,State) -> 0..| {stop,State}; | handle_cast({storevar,Name,Value}, State = #state{var=D}) -> 1..| NewD= dict:store(Name,Value,D), 1..| {noreply, State#state{var=NewD}}; | handle_cast({storefunc,Name,Par,Desc,Text}, State = #state{func=F}) -> 3..| NewF= dict:store(Name,{Par,Desc,Text},F), 3..| {noreply, State#state{func=NewF}}; | handle_cast(Msg, State) -> 0..| io:format("calc_store received cast: ~p~n",[Msg]), 0..| {noreply, State}. | | handle_info({'EXIT',_P,shutdown},State) -> 0..| {stop,State}; | handle_info(Msg,State) -> 0..| io:format("calc_state received info: ~p~n",[Msg]), 0..| {noreply,State}. | | terminate(_Reason, _State) -> 0..| ok. | | code_change(_OldVsn, State, _Extra) -> 0..| {ok, State}.