Java 当父对象位于不同的包中时,模拟受保护的父对象方法

Java 当父对象位于不同的包中时,模拟受保护的父对象方法,java,unit-testing,mockito,powermock,powermockito,Java,Unit Testing,Mockito,Powermock,Powermockito,我需要在受测类的父类中模拟受保护的方法,但父类位于不同的包中,因此我的测试类无法访问该方法,因此我无法模拟它。对于这个问题,必须有一个不需要重构的解决方案 我需要使用Powermock和Mockito。这是罐子 mockito all 1.10.8 powermock核心1.6.1 powermock-module-junit4 1.6.1 powermock api mockito 1.6.1 junit 4.12 这是遗留代码,因此我无法重构,但这里是简化的代码 Parent.java

我需要在受测类的父类中模拟受保护的方法,但父类位于不同的包中,因此我的测试类无法访问该方法,因此我无法模拟它。对于这个问题,必须有一个不需要重构的解决方案

我需要使用Powermock和Mockito。这是罐子

  • mockito all 1.10.8
  • powermock核心1.6.1
  • powermock-module-junit4 1.6.1
  • powermock api mockito 1.6.1
  • junit 4.12
这是遗留代码,因此我无法重构,但这里是简化的代码

Parent.java

package parent;

public class Parent {

    // Want to mock this protected parent method from different package
    protected String foo() {

        String someValue = null;

        // Logic setting someValue

        return someValue;
    }
}
package child;

import parent.Parent;

public class Child extends Parent {

    String fooString = null;

    public String boo() {

        this.fooString = this.foo();

        String booString = null;

        // Logic setting booString

        return booString;
    }
}
package child;

import static org.mockito.Mockito.spy;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import parent.Parent;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Parent.class, Child.class })
public class ChildTest {

    // Class Under Test
    Child cut;

    @Before
    public void setUp() throws Exception {

        // Partial mock to mock methods in parent class
        cut = spy(new Child());

    }

    @Test
    public void testBoo() {

        // TODO: Need to mock cut.foo() but can't figure out how.

        // Following gives me this error: The method foo() from the type Parent is not visible
       Mockito.when(((Parent)cut).foo()).thenReturn("mockValue");

        // Test
        cut.boo();

        // Validations
        Assert.assertEquals(cut.fooString, "mockValue");

    }
}
Child.java

package parent;

public class Parent {

    // Want to mock this protected parent method from different package
    protected String foo() {

        String someValue = null;

        // Logic setting someValue

        return someValue;
    }
}
package child;

import parent.Parent;

public class Child extends Parent {

    String fooString = null;

    public String boo() {

        this.fooString = this.foo();

        String booString = null;

        // Logic setting booString

        return booString;
    }
}
package child;

import static org.mockito.Mockito.spy;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import parent.Parent;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Parent.class, Child.class })
public class ChildTest {

    // Class Under Test
    Child cut;

    @Before
    public void setUp() throws Exception {

        // Partial mock to mock methods in parent class
        cut = spy(new Child());

    }

    @Test
    public void testBoo() {

        // TODO: Need to mock cut.foo() but can't figure out how.

        // Following gives me this error: The method foo() from the type Parent is not visible
       Mockito.when(((Parent)cut).foo()).thenReturn("mockValue");

        // Test
        cut.boo();

        // Validations
        Assert.assertEquals(cut.fooString, "mockValue");

    }
}
ChildTest.java

package parent;

public class Parent {

    // Want to mock this protected parent method from different package
    protected String foo() {

        String someValue = null;

        // Logic setting someValue

        return someValue;
    }
}
package child;

import parent.Parent;

public class Child extends Parent {

    String fooString = null;

    public String boo() {

        this.fooString = this.foo();

        String booString = null;

        // Logic setting booString

        return booString;
    }
}
package child;

import static org.mockito.Mockito.spy;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import parent.Parent;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Parent.class, Child.class })
public class ChildTest {

    // Class Under Test
    Child cut;

    @Before
    public void setUp() throws Exception {

        // Partial mock to mock methods in parent class
        cut = spy(new Child());

    }

    @Test
    public void testBoo() {

        // TODO: Need to mock cut.foo() but can't figure out how.

        // Following gives me this error: The method foo() from the type Parent is not visible
       Mockito.when(((Parent)cut).foo()).thenReturn("mockValue");

        // Test
        cut.boo();

        // Validations
        Assert.assertEquals(cut.fooString, "mockValue");

    }
}

只需创建一个用于测试的新类,扩展您想要测试的类,并在那里重写您的方法

看起来是这样的:

public class ChildForTest extends Child{
     @Override
     protected String foo() {
         //mock logic here
    }
}
编辑: 若要避免新的类定义,可以使用匿名类

@Before
public void setUp() throws Exception {

    // Partial mock to mock methods in parent class
    cut = new Child(){
        @Override
        protected String foo(){
            //mock logic here
            return "";
        }
    };
}

只需创建一个用于测试的新类,扩展您想要测试的类,并在那里重写您的方法

看起来是这样的:

public class ChildForTest extends Child{
     @Override
     protected String foo() {
         //mock logic here
    }
}
编辑: 若要避免新的类定义,可以使用匿名类

@Before
public void setUp() throws Exception {

    // Partial mock to mock methods in parent class
    cut = new Child(){
        @Override
        protected String foo(){
            //mock logic here
            return "";
        }
    };
}

您可以使用PowerMock来模拟非公共方法

@RunWith(PowerMockRunner.class)
public class ChildTest {

    @Test
    public void testBoo() throws Exception {
        //given
        Child child = PowerMockito.spy(new Child());
        PowerMockito.when(child, "foo").thenReturn("mockValue");

        //when
        String boo = child.boo();

        //then
        Assert.assertEquals("boo+mockValue", boo);
    }
}

您可以使用PowerMock来模拟非公共方法

@RunWith(PowerMockRunner.class)
public class ChildTest {

    @Test
    public void testBoo() throws Exception {
        //given
        Child child = PowerMockito.spy(new Child());
        PowerMockito.when(child, "foo").thenReturn("mockValue");

        //when
        String boo = child.boo();

        //then
        Assert.assertEquals("boo+mockValue", boo);
    }
}

我不想重构任何Java。我只想编写一个新的单元测试类,并利用PowerMock和Mockito。您不必重构任何东西,只需创建一个新的类来模拟这个foo方法,而不是在测试中使用子对象,您可以使用ChildForTest对象,因为唯一的区别是方法foo()的方式但这是在引入一个新类。我所要做的就是涵盖Child.java的所有内容,而不涉及Parent.java。所以我想通过模仿Parent.java中的所有内容来涵盖Child.java。你可以使用我上面建议的解决方案来做到这一点。模仿框架在我看来被高估和过度使用了。你可以在Bob叔叔的文章(编写你自己的mocks.section)中读到这一点。我不想重构任何java。我只想编写一个新的单元测试类,并利用PowerMock和Mockito。您不必重构任何东西,只需创建一个新的类来模拟这个foo方法,而不是在测试中使用子对象,您可以使用ChildForTest对象,因为唯一的区别是方法foo()的方式但这是在引入一个新类。我所要做的就是涵盖Child.java的所有内容,而不涉及Parent.java。因此,我想通过模仿Parent.java中的所有内容来涵盖Child.java。你可以使用我上面建议的解决方案来实现这一点。在我看来,模仿框架被高估和过度使用了。你可以在Bob叔叔的文章中读到这一点(编写你自己的mocks.section)