The AVR-Libc user manual has an entire chapter on how to build a library. I would suggest starting there. If you use an IDE like eclipse, there will be project settings that are applicable if you want to build as a library instead of an executable.
Edit
Here's what eclipse does when I set it up for your example:
So that it couldn't be trivially compiled away, I changed your test_function to:
#include "test.h"
void test_function()
{
volatile int i = 0;
i++;
}
Building the library:
avr-gcc -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -std=gnu99 -funsigned-char -funsigned-bitfields -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"test.d" -MT"test.d" -c -o"test.o" "../test.c"
avr-ar -r "libtest.a" ./test.o
avr-objdump -h -S libtest.a >"libtest.lss"
avr-size --format=avr --mcu=atmega328p libtest.a
Building the main program
avr-gcc -I"C:\path\to\my\workspace\test" -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -std=gnu99 -funsigned-char -funsigned-bitfields -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"program.d" -MT"program.d" -c -o"program.o" "../program.c"
avr-gcc -Wl,-Map,MainProgram.map -L"C:\path\to\my\workspace\test\Release" -mmcu=atmega328p -o"MainProgram.elf" ./program.o -ltest
avr-objdump -h -S MainProgram.elf >"MainProgram.lss"
avr-size --format=avr --mcu=atmega328p MainProgram.elf
... and it builds without error. My guess is you need include paths specified in the command lines. Following proper naming conventions is pretty important too, try and follow the pattern above. Obviously the avr-objdump and avr-size commands are just for more information and not required if you're just building.
I'm pretty certain that if you'll need to recompile your library for specific target architectures and clock speeds as well.