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

标签 java spring unit-testing mockito instantiation

在使用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());


    }

}

房间.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;
    }

}

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!";
    }

}

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>

输出:(我为缺少的空间道歉)

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!

现在进行测试:

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));
    }

}

非常简单。

房间测试.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());
    }

}

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

最佳答案

内部静态类配置: 在测试 Spring 组件时,我们通常使用 @RunWith(SpringJUnit4ClassRunner.class) 并创建我们的类 @ContextConfiguration。通过创建类 @ContextConfiguration,您可以创建一个用于配置的内部静态类,您可以在其中完全控制。在那里,您将所有需要的定义为 beans 并在测试中将其定义为 @Autowired,以及依赖项,这些依赖项可以是模拟对象或常规对象,具体取决于测试用例。

组件扫描生产代码: 如果测试需要更多组件,您可以添加 @ComponentScan 但我们尝试让它只扫描它需要的包(这是当您使用 @Component 注释但在您的如果您可以将 XML 添加到 @ContextConfiguration)。当您不需要模拟并且您有一个需要像生产一样的复杂设置时,这是一个不错的选择。这对于集成测试非常有用,您可以在其中测试组件如何在要测试的功能切片中相互交互。

混合方法:当您有许多需要像生产一样但一两个需要模拟的 bean 时,这是通常的情况。然后你可以 @ComponentScan 生产代码,但添加一个内部静态类,它是 @Configuration 并在那里定义带有注释 @Primary 的 bean,这将覆盖生产测试时该 bean 的代码配置。这很好,因为您不需要为所有已定义的 bean 编写很长的 @Configuration,您可以扫描所需的内容并覆盖应该模拟的内容。

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

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());
    }

}

关于java - 使用 Spring 时实例化对象,用于测试与生产,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29203218/

相关文章:

java - 创建简单的 Spring AOP 时出现异常抛出建议演示

maven - 无法运行ElasticSearch测试

java - Java 中的 Mockito 'Misplaced argument detected here'

Javascript 和 JSP 未重新加载

java - 为什么在 Java 中跳过整数输入后的字符串输入?

java - 几个 DAO 层之间的事务?

java - 将用于Spring Boot应用程序的库放在额外的lib目录中

javascript - 我如何模拟 window.document 来测试以 DOM 为中心的 JavaScript?

java - 如何将数据插入到 SQLite 数据库表的开头?

java - 如何在android中另一个名为 "Activity A"的 Activity 中使用 "Activity B"的switch case中定义的方法?