最终项目路径如下:
第一个例子
假设有如下接口,
package service;
public interface Notice {
public void work(String message);
}
实现类如下,
package service;
public class NoticeImpl implements Notice {
@Override
public void work(String message) {
// TODO Auto-generated method stub
System.out.println(message);
}
}
单元测试类编写如下,
package iTest;
import org.junit.Test;
import demo.Factory;
import service.Notice;
import service.NoticeImpl;
public class TestRun {
@Test
public void helloWorld() {
Notice notice = new NoticeImpl();
System.out.println("hello world! " + notice);
}
@Test
public void work() {
Notice notice = new NoticeImpl();
notice.work("Hello Work");
}
}
此时,如果我觉得NoticeImpl实现不满意,想替换成NoticeNewImpl,这时测试组(或者调用者)需要重写代码(e.g. 将代码中所有的NoticeImpl替换成NoticeNewImpl)进行重编译等,存在冗余。
第二个例子
使用工厂模式,
package demo;
import service.Notice;
import service.NoticeImpl;
public class Factory {
public static Notice getNoticeInstance(){
return new NoticeImpl();
}
}
单元测试类改为,
package iTest;
import org.junit.Test;
import demo.Factory;
import service.Notice;
public class TestRun {
@Test
public void helloWorld() {
Notice notice = Factory.getNoticeInstance();
System.out.println("hello world! " + notice);
}
@Test
public void work() {
Notice notice = Factory.getNoticeInstance();
notice.work("Hello Work");
}
}
此时,仅需改动的代码只有1处。但替换NoticeNewImpl时还是需要重编译工厂类,有点麻烦。
第三个例子
借用配置文件applicationContext.property和类反射机制(面试题),工厂类改写如下(现在静态代码块加载env,面试题),
package demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import service.Notice;
public class Factory {
private static Properties env = new Properties();
static {
try (InputStream inputStream = Factory.class.getResourceAsStream("/resource/applicationContext.properties")) {
env.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Notice getNoticeInstance(){
Notice one = null;
try {
Class clazz = Class.forName(env.getProperty("Notice"));
one = (Notice) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
} finally {
return one;
}
}
}
配置文件applicationContext.property内容如下,
Notice = service.NoticeImpl
现在想替换NoticeNewImpl时仅需改写配置文件。此时,还有额外问题,即工厂类需要实现多个getXxxInstance方法,代码存在冗余。
第四个例子
升级为通用工厂,代码改写如下,
package demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import service.Notice;
public class Factory {
private static Properties env = new Properties();
static {
try (InputStream inputStream = Factory.class.getResourceAsStream("/resource/applicationContext.properties")) {
env.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getOneInstance(String interfaceName) {
Object one = null;
try {
Class clazz = Class.forName(env.getProperty(interfaceName));
one = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
} finally {
return one;
}
}
}
单元测试类(调用者代码)改写如下,
package iTest;
import org.junit.Test;
import demo.Factory;
import service.Notice;
public class TestRun {
@Test
public void helloWorld() {
Notice notice = (Notice) Factory.getOneInstance("Notice");
System.out.println("hello world! " + notice);
}
@Test
public void work() {
Notice notice = (Notice) Factory.getOneInstance("Notice");
notice.work("Hello Work");
}
}
配置文件applicationContext.property内容依旧如下,
Notice = service.NoticeImpl
OK,现在代码无耦合无冗余。
Reference
孙哥说Spring5(2020版) 6月30日 已更新 ~学不会Spring? 因为你没找对人(b站视频)
java的单元测试和集成spring单元测试