15

As I understand, lenient silences the exceptions thrown by StrictStubbing. Based on this, lenient shouldn't be used, maybe only temporary while doing TDD, because strict stubbing exceptions would generally mean that your code is either wrong, test is badly designed or you are adding unnecessary lines.

Is there a practical scenario where lenient is actually needed or useful for the test?

htafoya
  • 18,261
  • 11
  • 80
  • 104

5 Answers5

9

For example, it's very useful while migrating from Mockito 1 to Mockito 2 (the latter introduced strict stubbing), if you need to do it in a short period of time.

amseager
  • 5,795
  • 4
  • 24
  • 47
  • Mockito 1 is super old! (2016) – htafoya Mar 04 '20 at 19:22
  • 9
    2016 is not old lol. For example, there is a huge amount of enterprise apps that are still on Java 7 or so, especially in banking, not to mention specific libraries. Also, a lot of people prefer to migrate their Spring Boot projects only comprehensively with `spring-boot-dependencies` BOM, the 1st version of which (released in August 2019) contains Mockito 1. And don't forget about the bureaucracy which always slows down any plans to upgrade. Welcome to enterprise) – amseager Mar 04 '20 at 19:43
  • 1
    According to the question tags, you're more about the android development - ofc it's easier to upgrade these kind of apps (mobile apps are usually smaller). But even in this case, remember that the support of Java 8 was added only in 2017, as I recall. – amseager Mar 04 '20 at 19:47
8

Strict Stubbing is introduced to detect unnecessary stubs and write a much cleaner test. If you are getting exceptions, focus should be on improving test cases and not to by-pass strict stubbing check.

pinaci
  • 353
  • 4
  • 4
  • 5
    What if you have 10 test methods, 9 of which use the stubbing initialized in the @BeforeEach block. You get the stubbing exception on the 10th test case. Can't lenient be used to "fix" this? – David Dec 22 '21 at 07:55
  • 1
    You should not stub in the @BeforeEach then, try doing it in each test which needs it. – David Galvis Sandoval May 10 '22 at 15:24
  • 14
    @DavidGalvisSandoval Will it really be cleaner to place identical `when` in 9 (or more) tests compared to using `lenient()` in one place? Especially that this `when` might be a part of a larger block of `when`s, in which case extracting one of them to test methods will make the whole test class less readable. I think it should be a personal or team judgement. Every case is different, so you can't simply say "you should not", but rather: "consider, but feel free to break this rule when desired". Following "the rules" blindly is as worse as not following them at all. Keep balance. – itachi Jul 06 '22 at 10:14
8

A good example of when to use lenient is in a @BeforeEach block.

If you use the stub in almost all the test cases, it makes sense to create the stub in a before each. If you have any tests that don't use the stub, you'll need to use lenient to prevent the strict stubbing from throwing an error. This is the example used in the mockito docs:

  @Before public void before() {
      when(foo.foo()).thenReturn("ok");

      // it is better to configure the stubbing to be lenient:
      // lenient().when(foo.foo()).thenReturn("ok");

      // or the entire mock to be lenient:
      // foo = mock(Foo.class, withSettings().lenient());
  }

  @Test public void test1() {
      foo.foo();
  }

  @Test public void test2() {
      foo.foo();
  }

  @Test public void test3() {
      bar.bar();
  } 
Ryan Peterson
  • 519
  • 6
  • 7
5

I just came across an unusual valid use for this. We made a code change which disabled a feature by default (prior to taking it out altogether in a future release). We needed a test that the disabling actually worked, so we needed to mock some flag as false. However, we also needed to mock a few other values becaues, if the bit of code to disable the feature (which tested that flag) got broken somehow, the default settings for the feature would cause it to do nothing anyway, so we wouldn't be able to observe failure of the flag.

To summarise: in the success case, we would get UnnecessaryStubbingException with the mocking but, without it, the failure case wouldn't actually fail. Hence we marked those specific mockings as lenient.

HughG
  • 1,108
  • 10
  • 14
5

lenient() can also be useful if you're writing a parameterized test. Parameterized tests can reduce redundant code a lot more than strict stubbing can. So if you're using a parameterized test (to test all of your exceptional conditions, for example), you may want lenient() stubbing if some invocations need a stub while others don't. Make your stubs as specific as possible first though.

Samurai Soul
  • 235
  • 2
  • 9