Sergei Tachenov
Sergei Tachenov

Reputation: 24909

TestNG expectedExceptionsMessageRegExp and externalized messages

I'm using TestNG for my unit tests and I'd like to check exception messages. OK, @Test(expectedExceptionsMessageRegExp = ...) is exactly what I need, right? Well, at the same time I'd like to externalize my messages so they aren't mixed with my code. I'm loosely following a guide by Brian Goetz, so my exception code looks like

throw new IllegalArgumentException(MessageFormat.format(
    EXCEPTIONS.getString(EX_NOT_A_VALID_LETTER), c));

Works perfectly for me, except these two things don't exactly mix. I can't write

@Test(dataProvider = "getInvalidLetters",
    expectedExceptions = {IllegalArgumentException.class},
    expectedExceptionsMessageRegExp = regexize(EXCEPTIONS.getString(EX_NOT_A_VALID_LETTER)))

Here, regexize is a function that is supposed to replace {0}-style placeholders with .*. However, this fails with a “element value must be a constant expression”. Makes sense, since it's needed at compile time. But what are possible workarounds?

I can imagine a test code generator that would replace these constructs with real message regexps, but it would be a pain to integrate it with IDE, SCM, build tools and so on.

Another option is to use try-catch and check exception message manually. But this is ugly.

Lastly, I think it should be possible to hack TestNG with something like

@Test(expectedExceptionsMessageBundle = "bundle.name.goes.here",
      expectedExceptionsMessageLocaleProvider = "functionReturningListOfLocales"
      expectedExceptionsMessageKey = "MESSAGE_KEY_GOES_HERE")

This would be a great thing, really. Except that it won't be the same TestNG that Maven fetches for me from the repo. Another option is to implement this, contribute a patch to TestNG and wait for it to be released. I'm seriously considering this option now, but maybe there's an easier way? Haven't I missed something obvious? I can't possibly be the only one with this issue!

Or maybe I'm externalizing my messages in a wrong way. But a guy like Brian Goetz can't be wrong, now can he? Or did I get him wrong?

Update

Based on the answer given here, I've made a tutorial on the topic, covering some pitfalls, especially when using NetBeans 8.1.

Upvotes: 0

Views: 1285

Answers (1)

juherr
juherr

Reputation: 5740

Why not using an annotation transformer here?

You will be able to do something like:

@LocalizedException(expectedExceptionsMessageBundle = "bundle.name.goes.here",
      expectedExceptionsMessageLocaleProvider = "functionReturningListOfLocales"
      expectedExceptionsMessageKey = "MESSAGE_KEY_GOES_HERE")
@Test(dataProvider = "getInvalidLetters",
      expectedExceptions = {IllegalArgumentException.class)
public void test() {
  // ...
}

Where the annotation transformer will look like:

public class LocalizedExceptionTransformer implements IAnnotationTransformer {
  public void transform(ITest annotation, Class testClass,
      Constructor testConstructor, Method testMethod) {
    if (testMethod != null) {
      LocalizedException le = testMethod.getAnnotation(LocalizedException.class);
      if (le != null) {
         String regexp = regexize(le);
         annotation.setExpectedExceptionsMessageRegExp(regexp);
      }
    }
  }
}

Upvotes: 2

Related Questions