How to verify a method gets called with an object whose some fields may be anyObject() while others have a...












0















I'm using Mockito with ScalaTest. Consider this simplified example.



Model case class:



case class Batch(batchId: Long, 
timestamp: Option[LocalDateTime] = Some(LocalDateTime.now),
invoicesReceived: Option[Int])


In my test I'm mocking a class called BatchRepository which has a method with this signature:



def create(conn: Connection, batch: Batch): Long


Relevant bit of test code:



verify(batchRepository, times(1)).create(anyObject(),
Batch(anyLong(), anyObject(), Matchers.eq(Some(1))))
)


The beef is: I'd like to verify that the code under test calls the mocked repository method with whatever Connection and a Batch instance with whatever id and timestamp, but invoicesReceived being exactly Some(1).



Using Mockito, is this possible at all, and if so, how?



The production code creates a new Batch which sets the timestamp to current moment, so I think it's pretty much impossible to create a real Batch object in the test for the verify() call with the exact same timestamp. So at least for the timestamp I'd need anyObject().



I tried many variations, like wrapping the whole Batch in Matchers.eq(), but I haven't found anything that works:




Invalid use of argument matchers! 2 matchers expected, 4 recorded [...]




I'd be happy to hear I'm using matchers all wrong if there turns out to be some alternative way to use Mockito to test what I want. 🙂



(I was having hard time writing a good name for this question; please edit or leave a comment if you understand what I'm asking and can express it more succinctly.)










share|improve this question





























    0















    I'm using Mockito with ScalaTest. Consider this simplified example.



    Model case class:



    case class Batch(batchId: Long, 
    timestamp: Option[LocalDateTime] = Some(LocalDateTime.now),
    invoicesReceived: Option[Int])


    In my test I'm mocking a class called BatchRepository which has a method with this signature:



    def create(conn: Connection, batch: Batch): Long


    Relevant bit of test code:



    verify(batchRepository, times(1)).create(anyObject(),
    Batch(anyLong(), anyObject(), Matchers.eq(Some(1))))
    )


    The beef is: I'd like to verify that the code under test calls the mocked repository method with whatever Connection and a Batch instance with whatever id and timestamp, but invoicesReceived being exactly Some(1).



    Using Mockito, is this possible at all, and if so, how?



    The production code creates a new Batch which sets the timestamp to current moment, so I think it's pretty much impossible to create a real Batch object in the test for the verify() call with the exact same timestamp. So at least for the timestamp I'd need anyObject().



    I tried many variations, like wrapping the whole Batch in Matchers.eq(), but I haven't found anything that works:




    Invalid use of argument matchers! 2 matchers expected, 4 recorded [...]




    I'd be happy to hear I'm using matchers all wrong if there turns out to be some alternative way to use Mockito to test what I want. 🙂



    (I was having hard time writing a good name for this question; please edit or leave a comment if you understand what I'm asking and can express it more succinctly.)










    share|improve this question



























      0












      0








      0








      I'm using Mockito with ScalaTest. Consider this simplified example.



      Model case class:



      case class Batch(batchId: Long, 
      timestamp: Option[LocalDateTime] = Some(LocalDateTime.now),
      invoicesReceived: Option[Int])


      In my test I'm mocking a class called BatchRepository which has a method with this signature:



      def create(conn: Connection, batch: Batch): Long


      Relevant bit of test code:



      verify(batchRepository, times(1)).create(anyObject(),
      Batch(anyLong(), anyObject(), Matchers.eq(Some(1))))
      )


      The beef is: I'd like to verify that the code under test calls the mocked repository method with whatever Connection and a Batch instance with whatever id and timestamp, but invoicesReceived being exactly Some(1).



      Using Mockito, is this possible at all, and if so, how?



      The production code creates a new Batch which sets the timestamp to current moment, so I think it's pretty much impossible to create a real Batch object in the test for the verify() call with the exact same timestamp. So at least for the timestamp I'd need anyObject().



      I tried many variations, like wrapping the whole Batch in Matchers.eq(), but I haven't found anything that works:




      Invalid use of argument matchers! 2 matchers expected, 4 recorded [...]




      I'd be happy to hear I'm using matchers all wrong if there turns out to be some alternative way to use Mockito to test what I want. 🙂



      (I was having hard time writing a good name for this question; please edit or leave a comment if you understand what I'm asking and can express it more succinctly.)










      share|improve this question
















      I'm using Mockito with ScalaTest. Consider this simplified example.



      Model case class:



      case class Batch(batchId: Long, 
      timestamp: Option[LocalDateTime] = Some(LocalDateTime.now),
      invoicesReceived: Option[Int])


      In my test I'm mocking a class called BatchRepository which has a method with this signature:



      def create(conn: Connection, batch: Batch): Long


      Relevant bit of test code:



      verify(batchRepository, times(1)).create(anyObject(),
      Batch(anyLong(), anyObject(), Matchers.eq(Some(1))))
      )


      The beef is: I'd like to verify that the code under test calls the mocked repository method with whatever Connection and a Batch instance with whatever id and timestamp, but invoicesReceived being exactly Some(1).



      Using Mockito, is this possible at all, and if so, how?



      The production code creates a new Batch which sets the timestamp to current moment, so I think it's pretty much impossible to create a real Batch object in the test for the verify() call with the exact same timestamp. So at least for the timestamp I'd need anyObject().



      I tried many variations, like wrapping the whole Batch in Matchers.eq(), but I haven't found anything that works:




      Invalid use of argument matchers! 2 matchers expected, 4 recorded [...]




      I'd be happy to hear I'm using matchers all wrong if there turns out to be some alternative way to use Mockito to test what I want. 🙂



      (I was having hard time writing a good name for this question; please edit or leave a comment if you understand what I'm asking and can express it more succinctly.)







      scala unit-testing mockito scalatest hamcrest






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 10:59







      Jonik

















      asked Nov 20 '18 at 10:49









      JonikJonik

      51.5k55209316




      51.5k55209316
























          2 Answers
          2






          active

          oldest

          votes


















          1














          The problem is you are trying to verify two calls at once - create and Batch.apply. Can't do that.



          One way to do what you want is ArgumentCaptor:



          val captor = ArgumentCaptor.forClass(classOf[Batch])
          verify(batchRepository).create(any(), captor.capture)
          captor.getValue should matchPattern {
          case Batch(_, _, Some(1)) =>
          }
          // or just `captor.getValue.infoReceived shouldBe Some(1)`





          share|improve this answer


























          • Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

            – Jonik
            Nov 20 '18 at 12:28











          • Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

            – Jonik
            Nov 20 '18 at 12:31











          • Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

            – Dima
            Nov 20 '18 at 12:34



















          0














          Have you tried mockito-scala? it supports partial functions as matchers so you could just write



          verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))


          Or even better if you use the idiomatic syntax



          batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called





          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53391357%2fhow-to-verify-a-method-gets-called-with-an-object-whose-some-fields-may-be-anyob%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            The problem is you are trying to verify two calls at once - create and Batch.apply. Can't do that.



            One way to do what you want is ArgumentCaptor:



            val captor = ArgumentCaptor.forClass(classOf[Batch])
            verify(batchRepository).create(any(), captor.capture)
            captor.getValue should matchPattern {
            case Batch(_, _, Some(1)) =>
            }
            // or just `captor.getValue.infoReceived shouldBe Some(1)`





            share|improve this answer


























            • Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

              – Jonik
              Nov 20 '18 at 12:28











            • Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

              – Jonik
              Nov 20 '18 at 12:31











            • Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

              – Dima
              Nov 20 '18 at 12:34
















            1














            The problem is you are trying to verify two calls at once - create and Batch.apply. Can't do that.



            One way to do what you want is ArgumentCaptor:



            val captor = ArgumentCaptor.forClass(classOf[Batch])
            verify(batchRepository).create(any(), captor.capture)
            captor.getValue should matchPattern {
            case Batch(_, _, Some(1)) =>
            }
            // or just `captor.getValue.infoReceived shouldBe Some(1)`





            share|improve this answer


























            • Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

              – Jonik
              Nov 20 '18 at 12:28











            • Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

              – Jonik
              Nov 20 '18 at 12:31











            • Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

              – Dima
              Nov 20 '18 at 12:34














            1












            1








            1







            The problem is you are trying to verify two calls at once - create and Batch.apply. Can't do that.



            One way to do what you want is ArgumentCaptor:



            val captor = ArgumentCaptor.forClass(classOf[Batch])
            verify(batchRepository).create(any(), captor.capture)
            captor.getValue should matchPattern {
            case Batch(_, _, Some(1)) =>
            }
            // or just `captor.getValue.infoReceived shouldBe Some(1)`





            share|improve this answer















            The problem is you are trying to verify two calls at once - create and Batch.apply. Can't do that.



            One way to do what you want is ArgumentCaptor:



            val captor = ArgumentCaptor.forClass(classOf[Batch])
            verify(batchRepository).create(any(), captor.capture)
            captor.getValue should matchPattern {
            case Batch(_, _, Some(1)) =>
            }
            // or just `captor.getValue.infoReceived shouldBe Some(1)`






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 20 '18 at 12:34

























            answered Nov 20 '18 at 11:50









            DimaDima

            24.5k32235




            24.5k32235













            • Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

              – Jonik
              Nov 20 '18 at 12:28











            • Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

              – Jonik
              Nov 20 '18 at 12:31











            • Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

              – Dima
              Nov 20 '18 at 12:34



















            • Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

              – Jonik
              Nov 20 '18 at 12:28











            • Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

              – Jonik
              Nov 20 '18 at 12:31











            • Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

              – Dima
              Nov 20 '18 at 12:34

















            Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

            – Jonik
            Nov 20 '18 at 12:28





            Awesome, thanks! I was using FunSuite so should matchPattern doesn't seem to be available but captor.getValue match and then case _ => fail seems clean enough.

            – Jonik
            Nov 20 '18 at 12:28













            Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

            – Jonik
            Nov 20 '18 at 12:31





            Why do you keep reverting the answer to any which does not compile in my case? Wouldn't it be more useful to have a version that will actually work as-is for me and future readers? (any produces "polymorphic expression cannot be instantiated to expected type"; any() works.)

            – Jonik
            Nov 20 '18 at 12:31













            Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

            – Dima
            Nov 20 '18 at 12:34





            Just mix in Matchers to get the matchPattern to work. As for any without parens, I guess, you are right ... Turns out I just have a workaround in my codebase: def any[T] = Matchers.any() for so long, that I forgot about it :) I was reverting it because I don't appreciate people editing my stuff without asking first.

            – Dima
            Nov 20 '18 at 12:34













            0














            Have you tried mockito-scala? it supports partial functions as matchers so you could just write



            verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))


            Or even better if you use the idiomatic syntax



            batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called





            share|improve this answer




























              0














              Have you tried mockito-scala? it supports partial functions as matchers so you could just write



              verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))


              Or even better if you use the idiomatic syntax



              batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called





              share|improve this answer


























                0












                0








                0







                Have you tried mockito-scala? it supports partial functions as matchers so you could just write



                verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))


                Or even better if you use the idiomatic syntax



                batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called





                share|improve this answer













                Have you tried mockito-scala? it supports partial functions as matchers so you could just write



                verify(batchRepository, times(1)).create(any, argMatching({case Batch(_, _, Some(1)) => }))


                Or even better if you use the idiomatic syntax



                batchRepository.create(*, argMatching({case Batch(_, _, Some(1)) => })) was called






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 28 '18 at 8:12









                BrunoBruno

                35128




                35128






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53391357%2fhow-to-verify-a-method-gets-called-with-an-object-whose-some-fields-may-be-anyob%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    MongoDB - Not Authorized To Execute Command

                    Npm cannot find a required file even through it is in the searched directory

                    in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith