nifi-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mark Payne <>
Subject Re: Error handling in @OnScheduled
Date Fri, 24 Aug 2018 15:00:58 GMT

You can certainly catch Throwable there, or AssertionError, more specifically, but I'd be
very wary
of doing that, because at that point you're really kind of working against the framework (both
nifi mock/test framework as well as the JUnit framework) instead of with it. If your intent
is to test
a specific method, I would recommend testing that method explicitly by calling it yourself.

You don't need to create your own MockProcessContext. You can get the ProcessContext from
the Test Runner. For example:

final MyProcessor myProcessor = new MyProcessor();
final TestRunner runner = TestRunners.newTestRunner(myProcessor);

runner.setProperty(MyProcessor.MY_PROPERTY, "hello");

try {
  myProcessor.onScheduled( runner.getProcessContext() );"Expected SomeException to get thrown from onScheduled method but it did not.");
} catch (final SomeException e) {
  // expected.

Now, this being said, it begs the question whether or not you want to be throwing an Exception
from your @OnScheduled method.
I'm sure there are use cases where this makes perfect sense. However, you should first think
about whether or not you are
able to prevent the Exception from occurring by applying validation rules (addValidator()
to PropertyDescriptor's or customValidate).
The benefit to validators here is that when the user configures the Processor incorrectly,
they get a clear indication immediately that it
is not valid and a clear explanation of why it's not valid (as well as being shown in the
Invalid Counts of Process Groups, etc.).
If you wait until the user tries to start the Processor and throw an Exception, it will be
less obvious that there's a configuration problem
and the error message that they receive is likely not to be as clear.


On Aug 23, 2018, at 5:25 PM, James Srinivasan <<>>

Ah, hadn't spotted that. It's close, but the Throwable I get is a
java.lang.AssertionError (Could not invoke methods annotated with
@OnScheduled annotation due to:
java.lang.reflect.InvocationTargetException) and there doesn't seem to
be any way to get the actual underlying exception my code threw in
order to properly validate it.

Mark's suggestion of calling the @OnScheduled method directly seems a
little tricky when using the TestRunner framework, or should I just
replicate the test setup (e.g. create my own MockProcessContext etc.)


On Thu, 23 Aug 2018 at 21:03, Mike Thomsen <<>>

James try it with a throwable like in my example
On Thu, Aug 23, 2018 at 10:51 AM Mark Payne <<>>


If you are expecting the method to throw an Exception and want to verify
that, you should
just call the method directly from your unit test and catch the Exception
there. The TestRunner
expects to run the full lifecycle of the Processor.


On Aug 23, 2018, at 10:49 AM, James Srinivasan <<>> wrote:

I tried that, but the problem is the exception is caught and the test
fails due to this:

try {
processor, context);
} catch (final Exception e) {
e.printStackTrace();"Could not invoke methods annotated with @OnScheduled
annotation due to: " + e);
On Thu, 23 Aug 2018 at 15:41, Mike Thomsen <>

For unit tests, if you're doing this to catch a failure scenario, you
should be able to wrap the failing call in something like this:

final def msg = "Lorem ipsum..."
def error = null
try {
} catch (Throwable t) {
  error = t
} finally {
  assertTrue(error.cause instanceof SomeException)

Obviously play around with the finally block, but I've had success with
that pattern.

On Thu, Aug 23, 2018 at 10:19 AM James Srinivasan <> wrote:

What is the best way to handle exceptions which might be thrown in my
@OnScheduled method? Right now, I'm logging and propagating the
exception which has the desired behaviour in NiFi (bulletin in GUI and
processor cannot be started) but when trying to add a unit test, the
(expected) exception is caught in and
failure asserted.

My actual @OnScheduled method builds a non-trivial object based on the
Processor's params - maybe I should be building that any time any of
the params change instead?

Many thanks,


  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message