Spring(二)——Junit测试工具、属性的注入方式、注解

1. Junit 测试工具

Junit 是一个 Java 编程语言的单元测试框架

常见的注解有:

  • @BeforeClass :表示使用此注解的方法在测试类被调用之前执行,在一个测试类中只能声明此注解一次,此注解对应的方法只能被执行一次。
  • @AfterClass :表示使用此注解的方法在测试类被调用结束退出之前执行,在一个测试类中只能声明此注解一次,并且此注解对应的方法只能被执行一次。
  • @Before:表示使用此注解的方法在每个@Test调用之前被执行,即一个类中有多少个@Test注解方法,那么@Before注解的方法就会被调用多少次。
  • @After:表示使用此注解的方法在每个@Test调用结束之后被执行,即一个类中有多少个@Test注解方法,那么@Before注解的方法就会被调用多少次。
  • @Test :表示使用此注解的方法为一个单元测试用例,在一个测试勒种可以多次声明此注解,每个注解为@Test的方法只被执行一次

Junit测试用例的完整的执行顺序:

  • @BeforeClass–>@Before–>@Test–>@After—>@AfterClass

测试验证:

  • 需要创建的类有如下红框标记:
    在这里插入图片描述

  • 先编写一个实体类Student

package com.zz.domain;

public class Student {

    private int id; //学号
    private String name; //姓名
    private String gender; //性别
    private String birthday; //出生日期
    private String major; //专业

    public Student() {
    }

    public Student(int id, String name, String gender, String birthday, String major) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.birthday = birthday;
        this.major = major;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", birthday='" + birthday + '\'' +
                ", major='" + major + '\'' +
                '}';
    }
}
  • 再编写applicationContext.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.xsd">

    <bean id="s1" class="com.zz.domain.Student">

    <property name="id" value="001"/>
    <property name="name" value="张一"/>
    <property name="gender" value="男" />
    <property name="birthday" value="2009-05-18"/>
    <property name="major" value="九阴真经" />
    </bean>

    <bean id="s2" class="com.zz.domain.Student">
        <property name="id" value="002"/>
        <property name="name" value="黄二"/>
        <property name="gender" value="男" />
        <property name="birthday" value="2011-07-08"/>
        <property name="major" value="如来神掌" />
    </bean>
</beans>
  • 编写测试类StudentDomainTest
package com.zz.domain;

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

public class StudentDomainTest {
    private static ApplicationContext context;

    //@BeforeClass,测试类的初始化过程,仅仅初始化一次。
    @BeforeClass
    public static void initContext(){
        System.out.println("执行了@BeforeClass的initContext()...");
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    //用来初始化测试用例的,每次测试都执行。
    @Before
    public void initTest(){
        System.out.println("执行了@Before的initTeset()...");
    }

    @After
    public void afterTest(){
        System.out.println("执行了@After的afterTeset()...");
    }

    //测试用例
    @Test
    public void testGetStudents1(){
        //初始化上下文(IOC容器)
        //ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("执行了@Test的testGetStudents1()...");
        Student s1 = (Student) context.getBean("s1");
        System.out.println(s1);
    }

    //测试用例
    @Test
    public void testGetStudents2(){
        //初始化上下文(IOC容器)
        //ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("执行了@Test的testGetStudents2()...");
        Student s2 = (Student) context.getBean("s2");
        System.out.println(s2);
    }

    @AfterClass
    public static void destroy(){
        System.out.println("执行了@AfterClass的destroy()...");
    }
}
  • 运行结果
    在这里插入图片描述

2. getBean的五种用法

(1)getBean(String id/name)
id不能重复,只能写一个,并且不能和name重复
name可写多个,并且也不能和id重复

<bean id="s1" class="com.zz.domain.Student">
<bean name="name1,name2,name3" class="com.zz.domain.Student">

需要进行类型转换

 Student s1 = (Student) context.getBean("s1");

(2)getBean(Class clazz)
通过类型加载,要求类型不能重复。好处是:无需类型转换

Student s1 = context.getBean(Student.class);

(3)getBean(String id/name,Class clazz);
通过id/name和类型查找,好处是:无需类型转换。

Student s1 = context.getBean("s1", Student.class);

(4)getBean(Class clazz,Object …objs)

Student s1 = context.getBean(Student.class,new Object[]{003,"胡三","女","1999-11-10","降龙十八掌"});

如果第二个参数是带对象数组的,一定是想返回使用对象数组初始化属性的对象。运行结果发现还是之前的对象。在这里插入图片描述
解决方法:通过工厂模式生成对象

工厂类 StudentFactory

package com.zz.factory;
import com.zz.domain.Student;
import java.lang.reflect.Constructor;

//使用工厂模式来生成学生。
public class StudentFactory {

    public static Student getStudentInstance(int sid,String sname,String gender,String birthday,String major) throws Exception{
        Class clazz = Class.forName("com.zz.domain.Student");
        //反射出构造方法。
        Constructor constructor = clazz.getConstructor(int.class,String.class,String.class,String.class,String.class);
        return (Student)constructor.newInstance(sid,sname,gender,birthday,major);
    }
}

applicationContext.xml文档

 <!--prototype 原型(非单例)-->
    <bean id="s1" factory-method="getStudentInstance" class="com.zz.factory.StudentFactory" scope="prototype">

        <constructor-arg name="id" value="111"/>
        <constructor-arg name="name" value=""/>
        <constructor-arg name="gender" value=""/>
        <constructor-arg name="birthday" value=""/>
        <constructor-arg name="major" value=""/>
    </bean>

运行结果
在这里插入图片描述
(5)getBean(String id/name,Object …objs)
与(4)方法相同,通过工厂方法生成对象,objs 初始化对象时的参数列表

3. 属性的注入方式

在实际项目开发时一般不配置applicationContext.xml,太麻烦,都是使用注解来注入
在applicationContext.xml中只需要开启注解:

<context:component-scan base-package="com.zz"/> 

xml配置:简单来说就是配置applicationContext.xml. 里面通过注入对象。

注解配置:类上面添加@Configuration注解,那么这个类作用等同于applicationContext.xml

@Bean 注解的作用等同于

(1)通过property注入

applicationContext.xml文档

 <bean id="s2" class="com.zz.domain.Student">
     <property name="id" value="002"/>
     <property name="name" value="黄二"/>
     <property name="gender" value="男" />
     <property name="birthday" value="2011-07-08"/>
     <property name="major" value="如来神掌" />
    </bean>
</beans>

测试类

  @Test
    public void testPropertiesInject(){
        //1.通过property注入
        Student s1 = (Student) context.getBean("s2");
        System.out.println(s1);  //Student{id=2, name='黄二', gender='男', birthday='2011-07-08', major='如来神掌'}
    }

(2)通过 constructor-arg 注入,本质是调用构造方法

applicationContext.xml文档

 <!--构造方法注入-->
    <bean name="hehe,haha" class="com.zz.domain.Student">
    <constructor-arg name="id" value="111"/>
    <constructor-arg name="name" value="郭三"/>
    <constructor-arg name="gender" value="男"/>
    <constructor-arg name="birthday" value="1999-09-10"/>
    <constructor-arg name="major" value="九阴真经"/>
    </bean>

测试类

@Test
    public void testPropertiesInject(){
        //通过构造方法注入
        Student s1 = (Student) context.getBean("haha");
        System.out.println(s1);  //Student{id=111, name='郭三', gender='男', birthday='1999-09-10', major='九阴真经'}
    }

(3)通过@Value 注解注入,不推荐这种
开启注解方法:在applicationContext.xml 中添加
<context:component-scan base-package=“com.zz”/>

<!--@Value注解注入-->
    <!--开启注解功能-->
    <context:component-scan base-package="com.zz"/>
    <bean name="hehe,haha" class="com.zz.domain.Student" scope="prototype">

    </bean>

Student类
在成员变量前都加@value(“xxx”),这样做会造成初始化任何一个Students对象,属性赋值都是一样的,所以不推荐使用。

@Value("777")
private int id; //学号
@Value("周六")
private String name; //姓名
@Value("男")
private String gender; //性别
@Value("1998-02-03")
private String birthday; //出生日期
@Value("吹牛逼")
private String major; //专业

测试类

@Test
    public void testPropertiesInject(){
        //通过 @Value注入
        Student s1 = (Student) context.getBean("haha");
        System.out.println(s1); //Student{id=777, name='周六', gender='男', birthday='1998-02-03', major='吹牛逼'}
    }

(4)通过@Bean 注入,配合@Configuration 使用
创建一个SpringConfiguration类

package com.zz.config;

import com.zz.domain.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//带@Configuration注解的类等同于applicationContext.xml
@Configuration
public class SpringConfiguration {

    //在IOC容器中初始化了一个id=haha的对象
    @Bean("haha")
    public Student getStudentsBean1(){
        Student s = new Student(666,"郭九","男","2009-10-10","画画");
        return s;
    }

    @Bean("xixi")
    public Student getStudentsBean2(){
        Student s = new Student(200,"陈三","女","2000-10-10","美术");
        return s;
    }
}

同样applicationContext.xml中只需要开启注解:
添加 <context:component-scan base-package=“com.zz”/>

测试类

@Test
    public void testPropertiesInject(){
        //通过 注解注入
        Student s1 = (Student) context.getBean("xixi");  
        //改为haha,得到的就是Student{id=666, name='郭九', gender='男', birthday='2009-10-10', major='画画'}
        System.out.println(s1); //Student{id=200, name='陈三', gender='女', birthday='2000-10-10', major='美术'}
    }

4. bean的生存范围和加载策略

生存范围:

  • scope有两个常用属性:singleton(单例)和prototype(原型)。默认情况下为singleton。

  • singleton:无论这个bean被取多少次,都是同一个对象

    <bean id="001" class="com.zz.domain.Student">
    
  • prototype:每次bean取的对象不同

    <bean id="001" class="com.zz.domain.Student" scope="prototype">
    
  • 对应的注解的写法:

     @Scope("singleton")  或  @Scope("prototype")
    

加载策略:

在实体类上添加

 @Component
 @Lazy(true/false)

@Lazy(true) 表示懒加载,用到的时候再调用构造方法来实例化bean,不用就不实例化
@Lazy(false) 表示积极加载,默认是false; 不管是否用到,都事先加载出来

5. 自定义属性的注入方式

如实体类People中带有复杂属性Car

创建两个实体类People和Car

package com.zz.domain;

public class Person {
    private String name;
    private String gender;
    private int age;
    private Car car;

    public Person() {
    }

    public Person(String name, String gender, int age, Car car) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.car = car;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}
package com.zz.domain;

public class Car {

    private String brand;
    private String color;
    private int price;

    public Car() {
    }

    public Car(String brand, String color, int price) {
        this.brand = brand;
        this.color = color;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
}

创建一个注解配置类 SpringConfiguration2

package com.zz.config;

import com.zz.domain.Car;
import com.zz.domain.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfiguration2  {
    @Bean("p1")
    public Person getPerson1(@Autowired Car car){
        //按类型注入一个Car
        return new Person("张三","男",30,car);
    }

    @Bean("car1")
    public Car getCar1(){
        return new Car("BMW","黑色",400000);
    }
}

创建 PersonDomainTest 测试类

package com.zz.domain;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonDomainTest {


    private static ApplicationContext context;

    //@BeforeClass,测试类的初始化过程,仅仅初始化一次。
    @BeforeClass
    public static void initContext(){
        System.out.println("执行了initContext..");
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
    
    @Test
    public void testGetPersonBean(){
        Person p = (Person) context.getBean("p1");
        System.out.println(p); //Person{name='张三', gender='男', age=30, car=Car{brand='BMW', color='黑色', price=400000}}
    }
}

6. Spring中各类注解的作用

@Component:添加在实体类,表示是一个组件
@Repository:添加在接口上,表示是接口
@Controller:添加在控制层上,表示是一个Controller,Controller属于SpringMVC的内容
@Service:添加在服务层上,表示是服务层代码
@Autowire:自动注入,根据类型
@Resource:自动注入,根据名字
@Bean:表示一个bean对象
@Configuration:配置注解
@Scope:生存范围
@Lazy:加载策略

发布了62 篇原创文章 · 获赞 2 · 访问量 2721

猜你喜欢

转载自blog.csdn.net/nzzynl95_/article/details/104340991