一、Junit
属于白盒测试
1. 普通测试麻烦说明
- 没有使用junit的时候缺点:
* 1.测试一定走main方法,是程序的入口,main方法的格式必须不能写错
* 2.要是在同一个main方法中测试的话,那么不需要测试的东西必须注释掉。
* 3.测试逻辑如果分开,需要定义多个测试类,麻烦
* 4.业务逻辑和测试代码,都混淆了
1. 代码
package com.fj.Junit.Junit;
public class Calculator {
//加法
public int add(int a, int b) {
return a + b;
}
//减法
public int sub(int a, int b) {
return a - b;
}
}
2. 调用代码
package com.fj.Junit.Junit;
public class Demo01 {
public static void main(String[] args) {
/*****************************************************************
* 没有使用junit的时候缺点:
* 1.测试一定走main方法,是程序的入口,main方法的格式必须不能写错
* 2.要是在同一个main方法中测试的话,那么不需要测试的东西必须注释掉。
* 3.测试逻辑如果分开,需要定义多个测试类,麻烦
* 4.业务逻辑和测试代码,都混淆了
* ***************************************************************
*/
//测试加法
Calculator cal = new Calculator();
int result = cal.add(10,20);
System.out.println(result);
int result1 = cal.sub(20,10);
System.out.println(result1);
}
}
2. Junit 的使用
1.使用说明
- 【1】一般测试和业务做一个分离,分离为不同的包:建议起名:公司域名倒着写+test
- 【2】测试类的名字: ****Test—>见名知意
- 【3】测试方法的定义->这个方法可以独立运行,不依托与main方法
- 名字:testAdd() testSub() 见名知意
- 参数:无参
- 返回值:无返回值
- 【4】测试方法定义完以后,不能直接就独立运行,必须要在方法前加入一个注解:@Test
- 【5】导入Junit的依赖环境:
- 【6】代码演示
```java
package com.fj.Junit.Junit;
import org.junit.Test;
/**
* 测试方法
*/
public class CalculatorTest {
@Test
public void testAdd() {
System.out.println("测试add方法");
Calculator cal = new Calculator();
int result = cal.add(10, 20);
System.out.println(result);
}
@Test
public void testSub() {
System.out.println("测试Sub方法");
Calculator cal = new Calculator();
int result = cal.sub(10, 20);
System.out.println(result);
}
}
- 【7】绿色正常,红色异常
- 【8】即使出现绿色接口,也不代表代码,通过,可能出现逻辑错误
- 【9】加入断言Assert.assertEquals:预测结果,判断一下我预测的结果和实际的结果是否一致
1. 如果疏忽吧加法携程成减法,如下代码
package com.fj.Junit.Junit;
public class Calculator {
//加法
public int add(int a, int b) {
//int num = 6 / 0;
return a - b;
}
//减法
public int sub(int a, int b) {
return a - b;
}
}
- 测试中加入断言,如下代码
package com.fj.Junit.Junit;
import org.junit.Assert;
import org.junit.Test;
/**
* 测试方法
*/
public class CalculatorTest {
@Test
public void testAdd() {
System.out.println("测试add方法");
Calculator cal = new Calculator();
int result = cal.add(10, 30);
// System.out.println(result); //程序的运行结果可以不关注
//加入断言:预测结果,判断一下我预测的结果和实际的结果是否一致:
Assert.assertEquals(40,result);
}
@Test
public void testSub() {
System.out.println("测试Sub方法");
Calculator cal = new Calculator();
int result = cal.sub(10, 20);
System.out.println(result);
}
}
- 返回结果:
测试add方法
java.lang.AssertionError:
Expected :40
Actual :-20
<Click to see difference>
at org.junit.Assert.fail(Assert.java:89)
at org.junit.Assert.failNotEquals(Assert.java:835)
at org.junit.Assert.assertEquals(Assert.java:647)
at org.junit.Assert.assertEquals(Assert.java:633)
at com.fj.Junit.Junit.CalculatorTest.testAdd(CalculatorTest.java:17)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Process finished with exit code -1
二、注解
1. 注解介绍
- 【1】 @Before: 在测试方法之间执行 ,一般会在@Before 修饰的那个方法中加入一些申请资源的代码:申请数据库资源,申请io资源,申请网络资源…
- 【2】@After: 在方法执行之后执行,一般会在@After修饰的那个方法中加入释放资源的代码:释放数据库资源,释放io资源,释放网络资源…
- 【3】@Override:限定重写父类方法,该注解只能用于方法。@Override的作用:限定重写的方法,只要重写方法有问题,就有错误提示
- 【4】@Deprecated:用于表示所修饰的元素(类,方法,构造器,属性等)已过时。通常是因为所修饰的结构危险或存在更好的选择。@Deprecated作用:在方法前加入@Deprecated,这个方法就会变成废弃、过期、过时方法
- 【5】@SuppressWarnings:抑制编辑器警告
@SuppressWarnings("unused") int age =10;
- 【6】代码演示
package com.fj.Junit.Junit;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* 测试方法
*/
public class CalculatorTest {
@Before
public void init() {
System.out.println("方法执行开始了..........");
}
@After
public void close(){
System.out.println("方法执行结束了..........");
}
@Test
public void testAdd() {
System.out.println("测试add方法");
Calculator cal = new Calculator();
int result = cal.add(10, 30);
// System.out.println(result); //程序的运行结果可以不关注
//加入断言:预测结果,判断一下我预测的结果和实际的结果是否一致:
Assert.assertEquals(40, result);
}
@Test
public void testSub() {
System.out.println("测试Sub方法");
Calculator cal = new Calculator();
int result = cal.sub(10, 20);
// System.out.println(result);
}
}
- 结果:
方法执行开始了..........
测试add方法
方法执行结束了..........
Process finished with exit code 0
- 【7】注意
2. 生成JvaDoc文档注解
- Tools-> Generate JAVADoc…
- 定义参数:其他参数:
-encoding utf-8 -charset utf-8
3. 自定义注解
【1】自定义注解使用很少,一般情况下都是现成的
【2】如何使用自定义注解:
定义注解的声明使用关键字是:@interface
package com.fj.Junit.anno;
/**
* 声明注解
*/
public @interface MyAnnotation {
}
【3】注解的内部:
- 以@SuppressWarnings为例,发现内部:
String[] value();
是属性还是方法?
答案:看上去是无参数方法,实际理解为一个成员变量,一个属性。
无参数方法名字—>成员变量的名字
无参数方法的返回值—>成员变量的类型
这个参数叫 配置参数
无参数方法的类型:基本数据类型(八种),String,枚举,注解类型,还可以是以上类型所对应的数组
ps:如果只有一个成员变量的话,就起名叫value
public @interface SuppressWarnings {
/**
* The set of warnings that are to be suppressed by the compiler in the
* annotated element. Duplicate names are permitted. The second and
* successive occurrences of a name are ignored. The presence of
* unrecognized warning names is <i>not</i> an error: Compilers must
* ignore any warning names they do not recognize. They are, however,
* free to emit a warning if an annotation contains an unrecognized
* warning name.
*
* <p> The string {@code "unchecked"} is used to suppress
* unchecked warnings. Compiler vendors should document the
* additional warning names they support in conjunction with this
* annotation type. They are encouraged to cooperate to ensure
* that the same names work across multiple compilers.
* @return the set of warnings to be suppressed
*/
String[] value();
}
【4】使用注解
- 使用注解的话,如果你定义了配置参数,就必须给赋值操作
- 如果只有一个参数,并且这个参数的名字为value的话,value=可以不写
- 如果你给配置参数设置了默认值,使用的时候无需传值
- 一个注解的内部可以不定义配置参数的
- 内部没有定义配置参数的注解->标记
- 内部定义配置参数的注解->元数据
- 定义注解代码:
package com.fj.Junit.anno;
/**
* 声明注解
*/
public @interface MyAnnotation {
//
String[] value();
}
- 使用注解代码
package com.fj.Junit.anno;
/**
* @author fj
*/
@MyAnnotation(value = {"dd","ee","ddd"})
public class Person {
}
- 使用注解,value=不写
package com.fj.Junit.anno;
/**
* @author fj
*/
@MyAnnotation({"dd","ee","ddd"})
public class Person {
}
- 配置参数默认值代码
package com.fj.Junit.anno;
public @interface MyAnnotation2 {
String value() default "abc";
}
- 配置参数默认值调用代码
package com.fj.Junit.anno;
package com.fj.Junit.anno;
/**
* @author fj
*/
@MyAnnotation({"dd","ee","ddd"})
@MyAnnotation2
public class Person {
}
- 内部不定义配置参数的注解
package com.fj.Junit.anno;
public @interface MyAnnotation3 {
}
4. 元注解
元注解就是用于修饰其他注解的注解
举例:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
JDK5.0提供了四种元注解:Retention,Target,Documented,Inherited
五重注解说明:引用Gene Xu的五种注解博客,点击跳转
三、枚举
1. JDK1.5之前枚举类说明
在java中,类的对象是有限的,确定的。这个类我们可以定义为枚举类。
枚举类
package com.fj.Junit.test_enum;
/**
* 枚举类
*/
public class Season {
public String getSeasonName() {
return seasonName;
}
public void setSeasonName(String seasonName) {
this.seasonName = seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
public void setSeasonDesc(String seasonDesc) {
this.seasonDesc = seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
//属性
private String seasonName;//季节名称
private String seasonDesc;//季节描述
//利用构造器对属性进行赋值
//私有化
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//提供枚举类的有限的确定的对象:
public static final Season SPRING = new Season("春天", "春暖花开");
public static final Season SUMMER = new Season("夏天", "烈日洋洋");
public static final Season AUTUMN = new Season("秋天", "硕果累累");
public static final Season WINTER = new Season("冬天", "冰天雪地");
}
调用枚举类:
package com.fj.Junit.test_enum;
public class Demo01 {
public static void main(String[] args) {
Season summer = Season.SUMMER;
System.out.println(summer);
System.out.println(summer.getSeasonName());
}
}
2. JDK1.5之后枚举类
- 确定的对象–> enum枚举类要求对象(常量)必须放在最开始的位置,多个对象之间用,隔开,最后一个用;
- 用enum修饰
- enum关键字对应的枚举类的上次父类实:java.lang.Enum
- 但是我们自定义的枚举类的上层父类,是objetc
package com.fj.Junit.test_enum2;
/**
* 枚举类
*/
public enum Season {
//确定的对象--> enum枚举类要求对象(常量)必须防砸最开始的位置,多个对象之间用,隔开,最后一个用;
SPRING("春天", "春暖花开"),
SUMMER("夏天", "烈日洋洋"),
AUTUMN("秋天", "硕果累累"),
WINTER("冬天", "冰天雪地");
public String getSeasonName() {
return seasonName;
}
public void setSeasonName(String seasonName) {
this.seasonName = seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
public void setSeasonDesc(String seasonDesc) {
this.seasonDesc = seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
//属性
private String seasonName;//季节名称
private String seasonDesc;//季节描述
//利用构造器对属性进行赋值
//私有化
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
}
调用枚举类
package com.fj.Junit.test_enum2;
public class Demo01 {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
//enum关键字对应的枚举类的上次父类实:java.lang.Enum
//但是我们自定义的枚举类的上层父类,是objetc
System.out.println(Season.class.getSuperclass().getName());
}
}
3. 空枚举类
为什么这么简单:因为这个枚举类底层没有属性,构造器,toSting,get方法,然后按理来说应该写为SPRINT() ,现在脸()可以省略,就变成SPRINT
package com.fj.Junit.test_enum3;
/**
* 枚举类
*/
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
4. Enum方法
package com.fj.Junit.test_enum3;
public class Demo01 {
public static void main(String[] args) {
//用enum关键字创建的season枚举类上面的父类实:java.lang.Enum,常用方法子类Season可以直接拿过来使用
//toString() 获取对象的名字
Season autumn = Season.AUTUMN;
System.out.println(autumn);
System.out.println("======================");
//values 返回枚举类对象的数组
Season[] values = Season.values();
for(Season s:values){
System.out.println(s);
}
System.out.println("======================");
//valueOf 注意:对象的名字必须正确。
//通过对象名字获取这个枚举对象
Season autumn1 = Season.valueOf("AUTUMN");
System.out.println(autumn1);
}
}
5. 枚举类实现接口
1.枚举类实现接口
【1】定义一个接口
package com.fj.Junit.test_enum4;
/**
* 接口
*/
public interface Demo01 {
void Show();
}
【2】枚举类实现这个接口
package com.fj.Junit.test_enum4;
/**
* 枚举类
*/
public enum Season implements Demo01 {
SPRING,
SUMMER,
AUTUMN,
WINTER;
@Override
public void Show() {
System.out.println("Show");
}
}
【3】测试类:
所有的枚举对象,调用这个show方法的时候走得都是同一个方法,结构也是相同的
package com.fj.Junit.test_enum4;
public class Test {
public static void main(String[] args) {
Season autumn = Season.AUTUMN;
autumn.Show();
Season summer = Season.SUMMER;
summer.Show();
}
}
结果:
Show
Show
Process finished with exit code 0
2. 枚举类实现接口各自实现接口方法
【1】接口类
package com.fj.Junit.test_enum4;
/**
* 接口
*/
public interface Demo01 {
void Show();
}
【2】枚举类
package com.fj.Junit.test_enum4;
/**
* 枚举类
*/
public enum Season implements Demo01 {
SPRING{
@Override
public void Show() {
System.out.println("这是春天");;
}
},
SUMMER{
@Override
public void Show() {
System.out.println("这是夏天");
}
},
AUTUMN{
@Override
public void Show() {
System.out.println("这是秋天");
}
},
WINTER{
@Override
public void Show() {
System.out.println("这是冬天");
}
};
/* @Override
public void Show() {
System.out.println("Show");
}*/
}
【3】 测试类
package com.fj.Junit.test_enum4;
public class Test {
public static void main(String[] args) {
Season autumn = Season.AUTUMN;
autumn.Show();
Season summer = Season.SUMMER;
summer.Show();
}
}
结果:
这是秋天
这是夏天
Process finished with exit code 0
6. 枚举的应用
1. 应用1
- 枚举类
package com.fj.Junit.test_enum5;
public enum Gender {
男,
女;
}
- 普通类
package com.fj.Junit.test_enum5;
public class Person {
//属性
private int age;
private String name;
private Gender sex;
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
- 测试类
package com.fj.Junit.test_enum5;
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setAge(19);
p.setName("kk");
p.setSex(Gender.女);//传入枚举类对象-->在入口处对参数进行了限制
System.out.println(p);
}
}
结果:
Person{age=19, name='kk', sex=女}
Process finished with exit code 0
2. 应用2:
- 枚举类:
package com.fj.Junit.test_enum5;
public enum Gender {
男,
女;
}
- 测试类
package com.fj.Junit.test_enum5;
public class Demo02 {
public static void main(String[] args) {
Gender sex = Gender.男;
//switch 后面()中可以传入枚举类型
//switch 后面() :int,short,byte,char,String,枚举类型
switch (sex){
case 女:
System.out.println("女");
break;
case 男:
System.out.println("男");
break;
}
}
}