Leaving aside the fact that you don't modify test in this loop and it will never be >250, there's a couple of ways to treat this.
Any code with goto can be written without goto. Theoretically - I think Wirth proved this as a mathematical fact. But sometimes, using a goto makes a lot of sense. To rewite this without goto, you need to check the condition in each loop:
void loop() {
for (r = 0; r < 255 && test <= 250; r++) {
for (g = 255; g > -1 && test <= 250; g--) {
for (b = 0; b < 255 && test <= 250; b++) {
Serial.println("do something");
}
}
}
Serial.println("works");
}
Using a goto is clearer and neater.
Java supports breaking out of neeply nested loops, C++ doesn't.
Another way to do this is to make use of the behaviour of the return statement:
void loop() {
findSolution();
Serial.println("works");
}
void findSolution() {
for (r = 0; r < 255; r++) {
for (g = 255; g > -1; g--) {
for (b = 0; b < 255; b++) {
if (test > 250)
return;
Serial.println("do something");
}
}
}
}
But this is something of a hack: the loops possibly don't really belong in a separate function. The goto is neat, makes sense, and is not "spaghetti code". I used to code BASIC back in the 80's, I know what spaghetti code actually looks like. This isn't - it's simply exiting out of a deeply nested loop.