Powermock: How to mock a method in an enumeration constant












1














I have an enumeration type which I used as a collection of factories for other objects that implement a common interface. A simplified version of the code is:



interface Operation { 
void execute();
}

enum Factory {
TYPE1(Class1::new),
TYPE2(Class2::new);

private Supplier<Operation> constructor;

Factory(Supplier<Operation> constructor) {
this.constructor = constructor;
}

Operation build() {
return constructor.get();
}
}


A simplified version of the client code looks like:



class Client {
private void run(EnumSet<Factory> required) {
for (Factory x : required) {
x.build().execute();
}
}

// Some code that calls run() with the right EnumSet
}


This all appears to work as expected, so I want to write some Unit tests.



Testing the Factory is easy, but the Client is proving more difficult. The problem is that I don't want to start calling the Operation (they do a lot of work). Instead I'd like to get x.build() return a mock object.



I've tried using PowerMocks whenNew to trap the creation of the Operation objects, but this doesn't work (I don't actually have any 'new' operations). I've also tried to use a Powermock 'spy', but this fails because the enumeration constants are real objects.



Any ideas?










share|improve this question






















  • Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
    – GhostCat
    Nov 15 at 15:50










  • Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
    – Stormcloud
    Nov 16 at 11:15










  • I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
    – GhostCat
    Nov 16 at 11:30










  • For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
    – Stormcloud
    Nov 16 at 11:58
















1














I have an enumeration type which I used as a collection of factories for other objects that implement a common interface. A simplified version of the code is:



interface Operation { 
void execute();
}

enum Factory {
TYPE1(Class1::new),
TYPE2(Class2::new);

private Supplier<Operation> constructor;

Factory(Supplier<Operation> constructor) {
this.constructor = constructor;
}

Operation build() {
return constructor.get();
}
}


A simplified version of the client code looks like:



class Client {
private void run(EnumSet<Factory> required) {
for (Factory x : required) {
x.build().execute();
}
}

// Some code that calls run() with the right EnumSet
}


This all appears to work as expected, so I want to write some Unit tests.



Testing the Factory is easy, but the Client is proving more difficult. The problem is that I don't want to start calling the Operation (they do a lot of work). Instead I'd like to get x.build() return a mock object.



I've tried using PowerMocks whenNew to trap the creation of the Operation objects, but this doesn't work (I don't actually have any 'new' operations). I've also tried to use a Powermock 'spy', but this fails because the enumeration constants are real objects.



Any ideas?










share|improve this question






















  • Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
    – GhostCat
    Nov 15 at 15:50










  • Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
    – Stormcloud
    Nov 16 at 11:15










  • I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
    – GhostCat
    Nov 16 at 11:30










  • For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
    – Stormcloud
    Nov 16 at 11:58














1












1








1







I have an enumeration type which I used as a collection of factories for other objects that implement a common interface. A simplified version of the code is:



interface Operation { 
void execute();
}

enum Factory {
TYPE1(Class1::new),
TYPE2(Class2::new);

private Supplier<Operation> constructor;

Factory(Supplier<Operation> constructor) {
this.constructor = constructor;
}

Operation build() {
return constructor.get();
}
}


A simplified version of the client code looks like:



class Client {
private void run(EnumSet<Factory> required) {
for (Factory x : required) {
x.build().execute();
}
}

// Some code that calls run() with the right EnumSet
}


This all appears to work as expected, so I want to write some Unit tests.



Testing the Factory is easy, but the Client is proving more difficult. The problem is that I don't want to start calling the Operation (they do a lot of work). Instead I'd like to get x.build() return a mock object.



I've tried using PowerMocks whenNew to trap the creation of the Operation objects, but this doesn't work (I don't actually have any 'new' operations). I've also tried to use a Powermock 'spy', but this fails because the enumeration constants are real objects.



Any ideas?










share|improve this question













I have an enumeration type which I used as a collection of factories for other objects that implement a common interface. A simplified version of the code is:



interface Operation { 
void execute();
}

enum Factory {
TYPE1(Class1::new),
TYPE2(Class2::new);

private Supplier<Operation> constructor;

Factory(Supplier<Operation> constructor) {
this.constructor = constructor;
}

Operation build() {
return constructor.get();
}
}


A simplified version of the client code looks like:



class Client {
private void run(EnumSet<Factory> required) {
for (Factory x : required) {
x.build().execute();
}
}

// Some code that calls run() with the right EnumSet
}


This all appears to work as expected, so I want to write some Unit tests.



Testing the Factory is easy, but the Client is proving more difficult. The problem is that I don't want to start calling the Operation (they do a lot of work). Instead I'd like to get x.build() return a mock object.



I've tried using PowerMocks whenNew to trap the creation of the Operation objects, but this doesn't work (I don't actually have any 'new' operations). I've also tried to use a Powermock 'spy', but this fails because the enumeration constants are real objects.



Any ideas?







java unit-testing mocking powermock powermockito






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 at 14:51









Stormcloud

9941925




9941925












  • Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
    – GhostCat
    Nov 15 at 15:50










  • Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
    – Stormcloud
    Nov 16 at 11:15










  • I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
    – GhostCat
    Nov 16 at 11:30










  • For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
    – Stormcloud
    Nov 16 at 11:58


















  • Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
    – GhostCat
    Nov 15 at 15:50










  • Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
    – Stormcloud
    Nov 16 at 11:15










  • I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
    – GhostCat
    Nov 16 at 11:30










  • For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
    – Stormcloud
    Nov 16 at 11:58
















Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
– GhostCat
Nov 15 at 15:50




Any feedback on my answer? If you found it helpful, pls dont forget about accepting, otherwise let me know if I can add anything to it ...
– GhostCat
Nov 15 at 15:50












Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
– Stormcloud
Nov 16 at 11:15




Hi, I've been playing with the Powermock solution over the last couple of days, but I've not been able to get it to work :-( In the linked question the enumeration contained an abstract method which is why (I think) the individual constants have their own class. In this case there are no abstract methods, so the compiler only produces a single class file.
– Stormcloud
Nov 16 at 11:15












I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
– GhostCat
Nov 16 at 11:30




I see. But as said: I consider PowerMock(ito) to always be the last straw. If possible, change your production code, and make it easier to test. Anything else is using black magic to circumvent a designed-in deficiency.
– GhostCat
Nov 16 at 11:30












For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
– Stormcloud
Nov 16 at 11:58




For the moment my work around is to add a setter function to the enumeration constants so that build() can return prebuilt objects - my mocks. While it means I've only made a small change to the production code it does mean that my enumeration 'constant' is now mutable! This feels worse then the alternatives.
– Stormcloud
Nov 16 at 11:58












1 Answer
1






active

oldest

votes


















1














Two solutions:




  • you insist on using PowerMock(ito). Then the simple issue is: you are probably preparing the wrong class for test. You have to temper with those enum constants, and they are inner classes. But it is possible, see this answer for example.

  • you step back, and improve your production code, to make it easier to test.


For example like this:



interface OperationProvider { 
Operation build();
}


to be used like:



enum Factory implements OperationProvider {


And now you can change your client code to do



OperationProvider ourProvider = ...
whatever.build();...


The point is: when using dependency injection, you simply pass a mocked OperationProvider. This means that you can basically sidestep the need to mock with your enum completely. You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.






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%2f53283659%2fpowermock-how-to-mock-a-method-in-an-enumeration-constant%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Two solutions:




    • you insist on using PowerMock(ito). Then the simple issue is: you are probably preparing the wrong class for test. You have to temper with those enum constants, and they are inner classes. But it is possible, see this answer for example.

    • you step back, and improve your production code, to make it easier to test.


    For example like this:



    interface OperationProvider { 
    Operation build();
    }


    to be used like:



    enum Factory implements OperationProvider {


    And now you can change your client code to do



    OperationProvider ourProvider = ...
    whatever.build();...


    The point is: when using dependency injection, you simply pass a mocked OperationProvider. This means that you can basically sidestep the need to mock with your enum completely. You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.






    share|improve this answer


























      1














      Two solutions:




      • you insist on using PowerMock(ito). Then the simple issue is: you are probably preparing the wrong class for test. You have to temper with those enum constants, and they are inner classes. But it is possible, see this answer for example.

      • you step back, and improve your production code, to make it easier to test.


      For example like this:



      interface OperationProvider { 
      Operation build();
      }


      to be used like:



      enum Factory implements OperationProvider {


      And now you can change your client code to do



      OperationProvider ourProvider = ...
      whatever.build();...


      The point is: when using dependency injection, you simply pass a mocked OperationProvider. This means that you can basically sidestep the need to mock with your enum completely. You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.






      share|improve this answer
























        1












        1








        1






        Two solutions:




        • you insist on using PowerMock(ito). Then the simple issue is: you are probably preparing the wrong class for test. You have to temper with those enum constants, and they are inner classes. But it is possible, see this answer for example.

        • you step back, and improve your production code, to make it easier to test.


        For example like this:



        interface OperationProvider { 
        Operation build();
        }


        to be used like:



        enum Factory implements OperationProvider {


        And now you can change your client code to do



        OperationProvider ourProvider = ...
        whatever.build();...


        The point is: when using dependency injection, you simply pass a mocked OperationProvider. This means that you can basically sidestep the need to mock with your enum completely. You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.






        share|improve this answer












        Two solutions:




        • you insist on using PowerMock(ito). Then the simple issue is: you are probably preparing the wrong class for test. You have to temper with those enum constants, and they are inner classes. But it is possible, see this answer for example.

        • you step back, and improve your production code, to make it easier to test.


        For example like this:



        interface OperationProvider { 
        Operation build();
        }


        to be used like:



        enum Factory implements OperationProvider {


        And now you can change your client code to do



        OperationProvider ourProvider = ...
        whatever.build();...


        The point is: when using dependency injection, you simply pass a mocked OperationProvider. This means that you can basically sidestep the need to mock with your enum completely. You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 14 at 9:11









        GhostCat

        88.1k1684144




        88.1k1684144






























            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.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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%2f53283659%2fpowermock-how-to-mock-a-method-in-an-enumeration-constant%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

            Guess what letter conforming each word

            Port of Spain

            Run scheduled task as local user group (not BUILTIN)