Here is unit test with expectations:
import static java.util.Arrays.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;   
import org.junit.Test;
public class JoinerTest {
    private static final Converter<Person, String> PERSON_CONVERTER =
        new Converter<Person, String>() {
            @Override
            public String convert(Person object) {
                return object.getFirstName();
            }
    };
    @Test
    public void shouldPresentFirstNames() {
        // given
        Person person1 = new Person();
        person1.setFirstName("foo");
        Person person2 = new Person();
        person2.setFirstName("bar");
        Joiner<Person> joiner = new Joiner<Person>(", ", "\'");
        // when
        String firstNames = joiner.join(PERSON_CONVERTER,
                        asList(person1, person2));
        // then
        assertThat(firstNames, is("\'foo\', \'bar\'"));
    }
}
Converter is just an interface:
public interface Converter<F, T> {
    T convert(F object);
}
And finally Joiner:
public class Joiner<T> {
    private final String delimiter;
    private final String quote;
    public Joiner(String delimiter, String quote) {
        this.delimiter = delimiter;
        this.quote = quote;
    }
    public String join(Converter<T, String> converter, Iterable<T> objects) {
        StringBuilder builder = new StringBuilder();
        for (T object : objects) {
            String string = converter.convert(object);
            builder.append(quote);
            builder.append(string);
            builder.append(quote);
            builder.append(delimiter);
        }
        if (builder.length() > 0) {
            builder.setLength(builder.length() - delimiter.length());
        }
        return builder.toString();
    }
}
By using different converters it is easy to join properties of different types.