Make sure the method is not called

I want to check that the method is not running, and tried to do this with the setting Expectation times = 0; However, I do not get the expected behavior.

For example, the following test passes, although the Session#stop method is called, and the wait has the condition times = 0; :

 public static class Session { public void stop() {} } public static class Whatever { Session s = new Session(); public synchronized void method() { s.stop(); } } @Test public void testWhatever () throws Exception { new Expectations(Session.class) { @Mocked Session s; { s.stop(); times = 0; } //Session#stop must not be called }; final Whatever w = new Whatever(); w.method(); // this method calls Session#stop => the test should fail... // ... but it passes } 

Note. If I replaced the code with { s.stop(); times = 1; } { s.stop(); times = 1; } { s.stop(); times = 1; } , the test will pass too: I have to miss something obvious here ...

+4
source share
5 answers

The reason for the unexpected mocking behavior is that you accidentally used a partial mockery of a severely mocking type. In this case, recording the wait with times = <n> means that the first n matching calls will be mocked, and after that any additional calls will be made by the original "unmocked" method. With the usual mockery, you will get the expected behavior instead (i.e., UnexpectedInvocation obtained after n invocations).

The correct way to record a test:

 public static class Session { public void stop() {} } public static class Whatever { Session s = new Session(); public synchronized void method() { s.stop(); } } @Test public void testWhatever () { new Expectations() { @Mocked Session s; { s.stop(); times = 0; } }; final Whatever w = new Whatever(); w.method(); } 

Alternatively, it can also be written using a validation block, which is usually better suited for such situations:

 @Test public void testWhatever (@Mocked final Session s) { final Whatever w = new Whatever(); w.method(); new Verifications() {{ s.stop(); times = 0; }}; } 
+7
source

In this regard, I had problems with JMockit, times = 0 and the @Tested annotation.

With the @Tested annotation, you still have a β€œreal” class, so when registering expectations or checking (even with times = 0) in this real class, JMockit tries to execute this method. The solution is to partially mock the class while waiting:

 @Tested Session s; new Expectations(Session.class) {{ s.stop(); times = 0; } //Session#stop must not be called }; 

This is the only way I have found using times = 0 for methods from @Tested classes.

+1
source

From memory, something like

 verify( s , times(0) ).stop(); 

will work. The problem is that Session in Whatever not your @Mock 'ed one, but another object, so insert

 ws = s; 

before w.method() .

Greetings

0
source

I found a workaround with the MockUp class - below is the test below - I would still like to understand why the original approach did not work .

 @Test public void testWhatever () throws Exception { new MockUp<Session>() { @Mock public void stop() { fail("stop should not have been called"); } }; final Whatever w = new Whatever(); w.method(); } 
0
source

Try maxTimes instead, you can also refer to stop () in a static way:

 @Test public void test(@Mocked Session mockSession){ final Whatever w = new Whatever(); w.method(); new Verifications(){ { Session.stop(); maxTimes = 0; } }; } 
0
source

Source: https://habr.com/ru/post/1441153/


All Articles