因为Leader不建议占用上班时间搞这个,基本上都是加班搞的
在做这个事的过程中,对IntelliJ idea更加熟悉,回顾下Mocikitto中spy,mock,verify,when的使用,这次重构基本上是小步快走,层层分离
IntelliiJ idea:
重构手法:如果想把一个方法移动到另一个class中,可以通过method增加一个Class类型的参数,然后将光标放在方法名的任何字符上【若选中方法名,则F6会失效】,按F6,在弹出的对话框中选择预期的Class【因为这个方法的参数是其它类型的对象】
更改方法的参数个数时,可以会调用处更改,从上往下进行,或按Ctrl+F6在调用的GUI界面操作。IntelliJ Idea的自动操作往往留一些尾巴,譬如,删除一个构造函数的一个参数,参数赋值的字段和构造中赋值语句不会自动删除。
如果方法参数有多个,且参数类型差别不大,IntelliJ idea alt+Enter提供的修改可能是错误的,譬如你删除了第5个参数,Idea可能会把第4个参数删除了,然后更改实际函数中的参数名,造成参数错位,就会编译报错,这种情况建议使用Ctrl+F6的GUi界面来操作。
把一个方法通过F6移动到另一个Class时,Move操作成功后,移过去的方法如果使用了原来Class中的字段,就会编译不过。这种情况不用担心,一般的步骤是先移动,然后解决编译报错。
移动方法时,方法增加的Class一般不选择抽象方法,这样会把方法移动到抽象方法中,正确的做法是,增加的类型参数是预期的抽象类的子类,这样就可以了
在建工厂类或接口时,可以先写Class Name,然后使用Idea的快捷键来创建Class,Interface,Method,Field
去除if else 的常用方法是每个分支就是一个对象,然后实现相同的接口;把if else分支的判断逻辑放到Factory类,这样代码就清净了。
扩展性和可维护性都增加了,扩展性:如果增加或减少一种场景,只修改工厂类或增加或删除新类即可,与此不相关的场景不会影响 ,不用知道其它情景的实现,也不用重新测试这些没有涉及的场景。
并且 业务逻辑和每个场景都可以独立写测试用例。如果有重复代码,不仅看得见,更能去得掉。重复代码抽取到父类中即可。也可以定义一个接口,抽象类来实现,业务类再继承抽象类。重复的字段或方法放在抽象类中。
Idea中的快捷键:
Ctrl+Alt+F12:打开某个package;
Ctrl+F12:打开File Structure
Ctrl+Alt+B:接口的实现类,抽象类的子类
Alt+F7:查找使用字段,方法
Ctrl+E:最近使用的文件,在F6移动操作时很有用
Ctrl+Alt+LeftArrow键:上一个操作代码位置。很遗憾,远程桌面中无法使用,只能使用鼠标点击工具栏上的按钮
Ctrl+Shift:移动方法或字段或语句
在equals方法的左或右边的对象上按Alt+Enter,会出现Flip,来互换
Ctrl+B转到定义处,再按Ctrl+B,返回
Alt+insert:构造函数,get,set,overrider
Ctrl+Alt+T:surround with try catch
在方法或类上按Ctrl+shift+T,用来创建测试用例
Ctrl+P:查看方法参数
Ctrl+Q:查看API
Shift+F6:重命名
Ctrl+Alt+n:内联,即独立的方法整合到调用中,被内联的方法就去掉了
在进行重构操作的Class代码中按Ctrl+Z,即可undo刚才的操作
compare with clipboard:先复制一段文本,然后在idea中选中一段文字,在选中文字上右键,选“Compare with clipboard”即可比较,identical:相同的,一致的
Ctrl+Shift+F9:compile,要做中Module或Project,光标在一个Class文件中,就会只编译这个文件,如果引用其它非APIclass,则编译不过
Idea中有在跑测试用例,编译Module或Project时,才会发现哪些Class中没有编译过。提交代码前一定要先编译下或先跑下测试用例
git:
git fetch//获取origin上的更新
git merge//和本地代码合并,如果有clifict,还要resolve才能提交
git add .//添加本地所有文件
git status -s//查看本地文件状态,如果没有输出,说明都处理过了。
git commit -m "注释"//提交到本地仓库
git push origin master//提交到git服务器的master分支
git branch//查看
git log --oneline -5
测试用例中mock使用的回顾:
spy,如果不想执行spy的方法,就使用doReturn,不然,被spy的方法还会被执行
直接贴个例子吧,
import com.download.util.Subnet; import com.file.utils.StmImManageImp; import com.file.utils.FileInfoUtil; import com.api.util.DebugPrn; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.io.File; import java.io.IOException; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class)//这个必须有,不然@Mock就失效了 public class StmFileExporterTest extends AbstractFileExportTest {//UT也需要去除重复 private static final DebugPrn LOGGER = new DebugPrn(StmFileExporterTest.class.getName()); private String targetPath; @Mock//使用Mock注解,代码更清晰 private FileInfoUtil fileStyle; @Mock private StmImManageImp ImManageImp; @Before//准备工作 public void init() throws IOException { targetPath = StmFileExporterTest.class.getResource("/com/file/fileexporter/").getPath(); if (!new File(targetPath).mkdirs()) { LOGGER.info(String.format("path(%s) mkdirs failed!", targetPath)); } } @Test public void should_doDataClearWork_deleteTempPath_when_getByDataType_is_true_and_saveFile_not_exists() {//方法名体现场景 try { when(fileStyle.getTaskName()).thenReturn("task1");//mock掉方法的返回值 String localTempPah = targetPath + fileStyle.getTaskName() + File.separator + "" + File.separator; Subnet spySubnet = spy(getGv3Subnet());//spy一个对象,因为这个对象中的 File localTempFle = new File(localTempPah); if (!localTempFle.mkdirs()) { LOGGER.info(String.format("path(%s) mkdirs failed!", localTempFle)); } StmFileExporter StmFileExporter = new StmFileExporter(targetPath, fileStyle); StmFileExporter spy = spy(StmFileExporter); spy.setImManageImp(ImManageImp);
//Mock方法中要匹配某个参数,需使用eq();doReturn,不执行mock的相关方法 doReturn(true).when(spy).getDataByDataType(eq(spySubnet), anyString(), anyString());
spy.sync(spySubnet); verify(ImManageImp).doData(); verify(ImManageImp).clearWork();//等价于verify(ImManageImp,times(1)).clearWork()
//Mockito的assertThat方法,可以把不匹配的expect和actual数据都打印出来,预期的数据需要使用is(),is()的功能也很强大 assertThat(localTempFle.exists(), is(false));
} catch (Exception e) { throw new IllegalArgumentException("UT Fail", e); } } @Test public void should_doDataClearWork_deleteTempPath_when_Type_not_equals_gv3() { try { Subnet spySubnet = spy(getNotGv3Subnet()); StmFileExporter StmFileExporter = new StmFileExporter(targetPath, fileStyle); StmFileExporter spy = spy(StmFileExporter); spy.sync(spySubnet); verify(spy, times(0)).doStmSync(spySubnet); } catch (Exception e) { throw new IllegalArgumentException("UT Fail", e); } } }
累并充实着吧。
就想起这么多了