如何撤消/重置PowerMockito.mockStatic?

时间:2018-02-16 16:52:18

标签: java static mocking powermock powermockito

假设我有以下课程

public class StaticClass {

    public static void staticMethod() throws SomeException {
        System.out.println("staticMethod");
    }

    private StaticClass() {
    }
}

public class SomeClass {

    public void someMethod() {
        try {
            StaticClass.staticMethod();
        }catch(SomeException ex) {
            System.out.println("SomeException occurred");
            return;
        }
        System.out.println("SomeException didn't occur");
    }
}

我正在使用

进行测试
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class SomeClassTest {

    @Test
    public void testStaticMethod() throws Exception {
        mockStatic(StaticClass.class);
        doThrow(new SomeException("unimportant message")).when(StaticClass.class,
                "staticMethod");
        //test something where exception is needed
        SomeClass instance = new SomeClass();
        try {
            instance.someMethod();
            fail("IllegalStateException expected");
        }catch(IllegalStateException expected) {
        }
        //now test something where exception isn't needed
        instance.someMethod();
    }
}

如何撤消静态模拟/配置以抛出SomeException,以便我可以在第二个instance.someMethod()中的try-catch块之后测试代码?

PowerMock: How to unmock a method?不适用,因为没有模拟引用传递给Mockito.reset并传递StaticClass会导致java.lang.ClassCastException: java.lang.Class cannot be cast to org.mockito.internal.creation.bytebuddy.MockAccess

SomeException只是扩展Exception

SSCCE在https://gitlab.com/krichter/powermock-undo-statik-mocking提供。

我正在使用PowerMock 1.7.3。

2 个答案:

答案 0 :(得分:2)

我的意见,但一般来说,单元测试应该使用单一的代码路径。 (我认为这是对测试方法应用单一责任。)

我的关于拆分测试的建议确实解决了这个问题。我不知道细节,但@PrepareForTest为每个测试提供了一个新的StaticClass

这些单独的测试有效:

@Test
public void testStaticMethodWhenSomethingUnexpectedHappens() throws Exception {
    mockStatic(StaticClass.class);
    // changed exception type
    doThrow(new IllegalStateException("unimportant message")).when(StaticClass.class, "staticMethod");

    SomeClass instance = new SomeClass();
    try {
        instance.someMethod();
        fail("IllegalStateException expected");
    } catch (IllegalStateException expected) {
    }

    // added verification
    verifyStaticMethodWasInvokedOneTime();
}

@Test
public void testStaticMethodHappyPath() throws Exception {
    mockStatic(StaticClass.class);
    doNothing().when(StaticClass.class, "staticMethod");

    SomeClass instance = new SomeClass();
    instance.someMethod();

    // added verification
    verifyStaticMethodWasInvokedOneTime();
}

private void verifyStaticMethodWasInvokedOneTime() throws SomeException {
    verifyStatic(StaticClass.class);
    StaticClass.staticMethod();
}

答案 1 :(得分:0)

对于任何想知道如何重置PowerMocks e.x的人。对于那些讨厌的私人静态最终记录器...

有一个issue(请参见接受的解决方案中的Karl的注释)来解决这个问题,解决方案是在方法级别使用@PrepareForTest。

因此在您的测试方法中,您需要注释

<div class="booking_form_request  
        <?php
        if($wpestate_options['sidebar_class']=='' || $wpestate_options['sidebar_class']=='none' ){
            print ' col-md-4 '; 
        }else{
            print esc_attr($wpestate_options['sidebar_class']);
        }
        ?>
         " id="booking_form_request">
        <div id="booking_form_request_mess"></div>
            <h3 ><?php esc_html_e('Book Now','wprentals');?></h3>

                <div class="has_calendar calendar_icon">
                    <input type="text" id="start_date" placeholder="<?php  echo wpestate_show_labels('check_in',$rental_type); ?>"  class="form-control calendar_icon" size="40" name="start_date" 
                            value="<?php if( isset($_GET['check_in_prop']) ){
                               echo sanitize_text_field ( $_GET['check_in_prop'] );
                            }
                            ?>">
                </div>

                <div class=" has_calendar calendar_icon">
                    <input type="text" id="end_date" disabled placeholder="<?php  echo wpestate_show_labels('check_out',$rental_type); ?>" class="form-control calendar_icon" size="40" name="end_date" 
                            value="<?php if( isset($_GET['check_out_prop']) ){
                               echo sanitize_text_field ( $_GET['check_out_prop'] );
                            }
                            ?>">
                </div>

                <?php 
                $max_guest = get_post_meta($post_id,'guest_no',true);
                if($rental_type==0){ 
                ?>
                    <div class=" has_calendar guest_icon ">
                        <?php 

                        print '
                        <div class="dropdown form-control">
                            <div data-toggle="dropdown" id="booking_guest_no_wrapper" class="filter_menu_trigger" data-value="';
                                if(isset($_GET['guest_no_prop']) && $_GET['guest_no_prop']!=''){
                                    echo esc_html( $_GET['guest_no_prop'] );
                                }else{
                                  echo 'all';
                                }
                            print '">';
                            print '<div class="text_selection">';
                            if(isset($_GET['guest_no_prop']) && $_GET['guest_no_prop']!=''){
                                echo esc_html( $_GET['guest_no_prop'] ).' '.esc_html__( 'guests','wprentals');
                            }else{
                                esc_html_e('Guests','wprentals');
                            }
                            print '</div>';

                            print '<span class="caret caret_filter"></span>
                            </div>           
                            <input type="hidden" name="booking_guest_no"  value="">
                            <ul  class="dropdown-menu filter_menu" role="menu" aria-labelledby="booking_guest_no_wrapper" id="booking_guest_no_wrapper_list">
                                '.$guest_list.'
                            </ul>        
                        </div>';//escaped above
                        ?> 
                    </div>
                <?php 
                }else{ 
                ?>
                   <input type="hidden" name="booking_guest_no"  value="1">
                <?php 
                }
                // shw extra options
                wpestate_show_extra_options_booking($post_id)
                ?>

                <p class="full_form " id="add_costs_here"></p>            

                <input type="hidden" id="listing_edit" name="listing_edit" value="<?php print intval($post_id);?>" />


                <?php wpestate_show_booking_button($post_id);?>


                <div class="third-form-wrapper">
                    <div class="col-md-6 reservation_buttons">
                        <div id="add_favorites" class=" <?php print esc_attr($favorite_class);?>" data-postid="<?php esc_attr(the_ID());?>">
                            <?php print trim($favorite_text);?>
                        </div>                 
                    </div>

                    <div class="col-md-6 reservation_buttons">
                        <div id="contact_host" class="col-md-6"  data-postid="<?php esc_attr(the_ID());?>">
                            <?php esc_html_e('Contact Owner','wprentals');?>
                        </div>  
                    </div>
                </div>

                <?php 
                echo wpestate_share_unit_desing($post_id);
                ?>



        </div>




     </div>
</div>

如果您想重置每个方法,只需将@PrepareForTest装饰器放在类而不是方法上