Spring 50例常见错误(十九)

文章整理来源:Spring编程常见错误50例_spring_spring编程_bean_AOP_SpringCloud_SpringWeb_测试_事务_Data-极客时间

案例47:Spring Test 扫描不到资源文件

        1. 定义 Controller ,2. 定义 HelloWorldService,3 在 /src/main/resource 下定义 spring.xml 文件,4. 定义 Configuration 引入 spring.xml 文件,5. 定义 SpringTest

// 1. 步骤 1 
@RestController
public class HelloController {

    @Autowired
    HelloWorldService helloWorldService;

    @RequestMapping(path = "hi", method = RequestMethod.GET)
    public String hi() throws Exception{
        return  helloWorldService.toString() ;
    };

}
-----------------------------------------------
// 2. 步骤 2
public class HelloWorldService {
}
-----------------------------------------------
// 3. 步骤 3
{"""


    
    

"""}
------------------------------------------------
// 4. 步骤 4
@Configuration
@ImportResource(locations = {"spring.xml"})
public class Config {
}
------------------------------------------------
// 5. 步骤 5
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyTestApplication.class)
public class TestApplication {
    @Autowired
    HelloController helloController;

    @Test
    public void testController() throws Exception {
        String response = helloController.hi();
        Assert.notNull(response, "not null");
    }
}

        程序抛出找不到 spring.xml 文件错误

        解析:1. 普通的启动程序使用的是 ClassPathResource#getInputStream 来加载 spring.xml 文

                2. 测试程序使用的是 MockServletContext#getResourceAsStream 来加载文件 spring.xml,而它会从 SpringBootMockServletContext#getResourceLocation() 方法中提供的路径去尝试加载文件

protected String getResourceLocation(String path) {
    if (!path.startsWith("/")) {
        path = "/" + path;
    }
    //加上前缀:/src/main/resources
    String resourceLocation = this.getResourceBasePathLocation(path);
    if (this.exists(resourceLocation)) {
        return resourceLocation;
    } else {
        //{"classpath:META-INF/resources", "classpath:resources", "classpath:static", "classpath:public"};
        String[] var3 = SPRING_BOOT_RESOURCE_LOCATIONS;
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String prefix = var3[var5];
            resourceLocation = prefix + path;
            if (this.exists(resourceLocation)) {
                return resourceLocation;
            }
        }

        return super.getResourceLocation(path);
    }
}

        它尝试从下面的一些位置进行加载:

classpath:META-INF/resources
classpath:resources
classpath:static
classpath:public
src/main/webapp

        而程序编译启动后的目录如下,从上面提供的路径中找不到 spring.xml

Spring 50例常见错误(十九)_第1张图片

         解决: 1. 建立一个 src/main/webapp,然后把 spring.xml 放入

                     2. 在 /src/main/resources 下面再建立一个 resources 目录,然后放入  spring.xml

                     3. 在 @ImportResource 使用 classpath 加载方式

@Configuration
//@ImportResource(locations = {"spring.xml"})
@ImportResource(locations = {"classpath:spring.xml"})
public class Config {
}

案例48:使用 @MockBean 导致 SpringContext 多次重新创建

        1. 定义被测试类和对应的测试程序

@Service
public class ServiceOne {
}
@Service
public class ServiceTwo {
}
---------------------------------
@SpringBootTest()
class ServiceOneTests {

    @MockBean
    ServiceOne serviceOne;

    @Test
    public void test(){
        System.out.println(serviceOne);
    }
}

@SpringBootTest()
class ServiceTwoTests {
    @MockBean
    ServiceTwo serviceTwo;
    @Test
    public void test(){
        System.out.println(serviceTwo);
    }
}

        解析:正常情况是不会重新创建一个 Spring Context 的。这是因为 Spring Test 使用了 Context 的缓存以避免重复创建 Context

        而 @MockBean 的使用会导致 TestContext 生成上下文的 Cache Key 变得不同

        解决:把相关的 MockBean 定义放到一个地方里

public class ServiceTests {
    @MockBean
    ServiceOne serviceOne;
    @MockBean
    ServiceTwo serviceTwo;

}

@SpringBootTest()
class ServiceOneTests extends ServiceTests{

    @Test
    public void test(){
        System.out.println(serviceOne);
    }

}

@SpringBootTest()
class ServiceTwoTests  extends ServiceTests{
    @Test
    public void test(){
        System.out.println(serviceTwo);
    }
}

你可能感兴趣的:(Spring,spring)