使用Spring时实例化对象,用于测试与生产

dwj*_*ton 5 java spring unit-testing instantiation mockito

我是否正确理解在使用Spring时,您应该使用Spring配置xml来实例化生产对象,并在测试时直接实例化对象?

例如.

MyMain.java

package org.world.hello;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMain {

    private Room room;


    public static void speak(String str)
    {
        System.out.println(str);
    }

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Room room = (Room) context.getBean("myRoom");

        speak(room.generatePoem());


    }

}
Run Code Online (Sandbox Code Playgroud)

Room.java

package org.world.hello;

public class Room {

    private BottleCounter bottleCounter;
    private int numBottles;

    public String generatePoem()
    {
        String str = "";
        for (int i = numBottles; i>=0; i--)
        {
            str = str +  bottleCounter.countBottle(i) + "\n";

        }
        return str;
    }

    public BottleCounter getBottleCounter() {
        return bottleCounter;
    }

    public void setBottleCounter(BottleCounter bottleCounter) {
        this.bottleCounter = bottleCounter;
    }

    public int getNumBottles() {
        return numBottles;
    }

    public void setNumBottles(int numBottles) {
        this.numBottles = numBottles;
    }

}
Run Code Online (Sandbox Code Playgroud)

BottleCounter.java

package org.world.hello;

public class BottleCounter {

    public String countBottle(int i)
    {
        return i + " bottles of beer on the wall" + i + " bottles of beer!";
    }

}
Run Code Online (Sandbox Code Playgroud)

beans.xml中:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="myRoom" class="org.world.hello.Room">
       <property name="bottleCounter">
            <bean id = "myBottleCounter" class = "org.world.hello.BottleCounter"/>     
       </property>
       <property name = "numBottles" value = "10"></property>

   </bean>

</beans>
Run Code Online (Sandbox Code Playgroud)

产出:(对遗失的空间表示歉意)

10 bottles of beer on the wall10 bottles of beer!
9 bottles of beer on the wall9 bottles of beer!
8 bottles of beer on the wall8 bottles of beer!
7 bottles of beer on the wall7 bottles of beer!
6 bottles of beer on the wall6 bottles of beer!
5 bottles of beer on the wall5 bottles of beer!
4 bottles of beer on the wall4 bottles of beer!
3 bottles of beer on the wall3 bottles of beer!
2 bottles of beer on the wall2 bottles of beer!
1 bottles of beer on the wall1 bottles of beer!
0 bottles of beer on the wall0 bottles of beer!
Run Code Online (Sandbox Code Playgroud)

现在测试一下:

BottleCounterTest.java:

package org.world.hello;

import static org.junit.Assert.*;

import org.junit.Test;

public class BottleCounterTest {

    @Test
    public void testOneBottle() {
        BottleCounter b = new BottleCounter();
        assertEquals("1 bottles of beer on the wall1 bottles of beer!", b.countBottle(1));
    }

}
Run Code Online (Sandbox Code Playgroud)

挺直的.

RoomTest.java:

package org.world.hello;

import static org.junit.Assert.*;
import org.mockito.Mockito;
import org.junit.Test;

public class RoomTest {

    @Test
    public void testThreeBottlesAreSeperatedByNewLines()
    {
        Room r = new Room();
        BottleCounter b = Mockito.mock(BottleCounter.class);
        Mockito.when(b.countBottle(Mockito.anyInt())).thenReturn("a");
        r.setBottleCounter(b);
        r.setNumBottles(3);
        assertEquals("a\na\na\na\n", r.generatePoem());
    }

}
Run Code Online (Sandbox Code Playgroud)

我是否正确地以这种方式实例化我的测试对象?

Nen*_*zic 20

内部静态类配置: 在测试Spring组件时,我们通常使用@RunWith(SpringJUnit4ClassRunner.class)并创建我们的类@ContextConfiguration.通过创建类,@ContextConfiguration您可以为配置创建内部静态类,并在其中完全控制.在那里,您可以根据@Autowired测试用例在测试中定义所需的所有bean和它,以及可以是模拟或常规对象的依赖项.

组件扫描生产代码: 如果测试需要更多组件,您可以添加,@ComponentScan但我们尝试仅扫描它需要的软件包(这是在您使用@Component注释时,但在您的情况下,您可以添加XML @ContextConfiguration).当你不需要模拟并且你有一个复杂的设置需要生产时,这是一个很好的选择.这对于集成测试很有用,在集成测试中,您要测试组件在要测试的功能片中如何相互交互.

混合方法:这是通常的情况,当你有许多豆需要生产,但一两个需要嘲笑.然后你可以@ComponentScan生成代码,但是添加一个内部静态类,它@Configuration定义带有注释的@Primarybean,在测试的情况下将覆盖该bean的生产代码配置.这很好,因为你不需要@Configuration用所有定义的bean 写长,你扫描你需要的东西并覆盖应该被模拟的东西.

在你的情况下,我会采用这样的第一种方法:

package org.world.hello;

import static org.junit.Assert.*;
import org.mockito.Mockito;
import org.junit.Test;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class RoomTest {

    @Configuration
    //@ImportResource(value = {"path/to/resource.xml"}) if you need to load additional xml configuration
    static class TestConfig {
       @Bean
       public BottleCounter bottleCounter() {
        return Mockito.mock(BottleCounter.class);
       }

       @Bean
       public Room room(BottleCounter bottleCounter) {
         Room room = new Room();
         room.setBottleCounter(bottleCounter);
         //r.setNumBottles(3); if you need 3 in each test
         return room;           
       }
    }

    @Autowired
    private Room room;  //room defined in configuration with mocked bottlecounter

    @Test
    public void testThreeBottlesAreSeperatedByNewLines()
    {
        Mockito.when(b.countBottle(Mockito.anyInt())).thenReturn("a");
        r.setNumBottles(3);
        assertEquals("a\na\na\na\n", r.generatePoem());
    }

}
Run Code Online (Sandbox Code Playgroud)


Koi*_*oer 5

通常,当您想要创建单元测试时,您需要记住:

  1. 你需要测试真实对象的代码,这意味着你想要单元测试的类需要是一个真实的实例,使用new运算符是不理想的,因为你可能在对象中有一些依赖,并且使用构造函数并不总是更好的方式.但你可以使用这样的东西.

    @Before
    public void init(){
       room = new Room(Mockito.mock(BottleCounter.class)); //If you have a constructor that receive the dependencies
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 需要模拟其他对象(也称为依赖项)的所有成员变量,任何has-a关系都需要用Mock对象替换,并且对这个模拟对象的方法的所有调用都应该被模拟 Mockito.when

如果你使用

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
Run Code Online (Sandbox Code Playgroud)

您将调用您的真正的bean并且不会进行单元测试,它将更像集成测试.在您从我的观点中写入问题的示例中,测试应该按以下方式进行:

@RunWith(MockitoJUnitRunner.class)
public class RoomTest {

@InjectMocks 
public Room room; //This will instantiate the real object for you
                  //So you wont need new operator anymore.

@Mock   //You wont need this in your class example
private AnyDependecyClass anyDependency;

@Test
public void testThreeBottlesAreSeperatedByNewLines(){
    BottleCounter b = Mockito.mock(BottleCounter.class);
    Mockito.when(b.countBottle(Mockito.anyInt())).thenReturn("a");
    room.setBottleCounter(b);
    room.setNumBottles(3);
    assertEquals("a\na\na\na\n", room.generatePoem());
   }
}
Run Code Online (Sandbox Code Playgroud)