Mark, Thanks very much for the detailed answer. In my particular case, I have a parameter corresponding to a schema file on disk and there is a standard validator to ensure that the file exists. Currently, in my @OnScheduled method, I read that schema file, parse it and store the parsed results in a member of my class ready for use in my onTrigger method. If the file fails to parse, an exception is thrown. I could move that code into a validator, but setting a member as a side effect of validation didn't quite feel right - does that makes sense?
James On Fri, 24 Aug 2018 at 16:01, Mark Payne <marka...@hotmail.com> wrote: > > James, > > 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 the > 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() ); > Assert.fail("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. > > Thanks > -Mark > > > On Aug 23, 2018, at 5:25 PM, James Srinivasan > <james.sriniva...@gmail.com<mailto:james.sriniva...@gmail.com>> wrote: > > 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.) > > Thanks, > > James > On Thu, 23 Aug 2018 at 21:03, Mike Thomsen > <mikerthom...@gmail.com<mailto:mikerthom...@gmail.com>> wrote: > > James try it with a throwable like in my example > On Thu, Aug 23, 2018 at 10:51 AM Mark Payne > <marka...@hotmail.com<mailto:marka...@hotmail.com>> wrote: > > James, > > 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. > > Thanks > -Mark > > > On Aug 23, 2018, at 10:49 AM, James Srinivasan < > james.sriniva...@gmail.com<mailto:james.sriniva...@gmail.com>> wrote: > > I tried that, but the problem is the exception is caught and the test > fails due to this: > > try { > ReflectionUtils.invokeMethodsWithAnnotation(OnScheduled.class, > processor, context); > } catch (final Exception e) { > e.printStackTrace(); > Assert.fail("Could not invoke methods annotated with @OnScheduled > annotation due to: " + e); > } > > > https://github.com/apache/nifi/blob/master/nifi-mock/src/main/java/org/apache/nifi/util/StandardProcessorTestRunner.java#L181 > On Thu, 23 Aug 2018 at 15:41, Mike Thomsen <mikerthom...@gmail.com> > wrote: > > 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 { > runner.run() > } catch (Throwable t) { > error = t > } finally { > assertNotNull(error) > assertTrue(error.cause instanceof SomeException) > assertTrue(error.cause.message.contains(msg)) > } > > 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 < > james.sriniva...@gmail.com> 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 StandardProcessorTestRunner.run 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, > > James > > > >