Mockito lenient() when to use
Asked Answered
S

6

26

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?

Sanious answered 26/2, 2020 at 18:20 Comment(0)
B
10

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.

Broth answered 4/3, 2020 at 9:12 Comment(3)
Mockito 1 is super old! (2016)Sanious
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)Broth
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.Broth
E
23

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();
  } 
Euridice answered 8/8, 2022 at 14:36 Comment(0)
B
10

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.

Broth answered 4/3, 2020 at 9:12 Comment(3)
Mockito 1 is super old! (2016)Sanious
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)Broth
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.Broth
T
7

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.

Turquoise answered 22/4, 2021 at 5:26 Comment(3)
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?Sushi
You should not stub in the @BeforeEach then, try doing it in each test which needs it.Heptane
@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 whens, 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.Budge
W
6

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.

Walz answered 29/1, 2021 at 9:40 Comment(0)
S
6

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.

Sensuous answered 29/12, 2022 at 20:8 Comment(1)
is strict stub checking only about redundant code, or is it more about logical correctness of tests ?Esbjerg
E
0

Similar case to what HughG wrote:

  1. a bug was reported
  2. a test was written to reproduce the bug, with a mock for this branch of execution
  3. the code was fixed/rewritten/extended
  4. the mock was no longer used in the test, so it was flagged by mockito
  5. the rewrite was buggy. This would have been spotted with the mock in-place, but a different branch was chosen without mock.

fix: lenient().mock(... for this single mock in this single test case, to guard against the test not failing even though it should.

Esbjerg answered 24/6 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.