Sure there is.
The question is is that a good idea?
#define MY_TEST(object, value, ...) do { test_case(object->value, #value , __VARARGS__); } while(false)
Code:
MY_TEST(mystruct, myvar1, ...);
MY_TEST(mystruct, myvar2, ...);
MY_TEST(mystruct, myvar3, ...);
Excplanation:
In the macro:
#define MY_TEST(object, value, ...)
The words: object and value become parameters to the macro. And are replaced identically in the expression on the right. If a parameter is prefixed with # then it is stringified by adding double quotes around it.
object->value, #value => object->value, "value"
Macros can also have a variable argument list represented by the ... which is replaced by using __VARARGS__ on the destination side. There is one limitation with using varargs in that it must match at least one parameter (i.e it can not match zero parameters (they may have fixed that but not sure)).
The reason to add the do { ... } while(false) is me being pedantic when using macros to make sure that the expression is treated like a statement. The compiler will optimize this away so there is no extra code and the statement is executed exactly once. I find it good practice to be overly careful and pedantic when using macros as there is little protection from the pre-processor (and the language has tried to evolve away from using macros in the first place).