package androidtest;
import entity.AndroidTestAction;
import entity.AndroidTestAssertion;
import entity.AndroidTestInfo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import utils.OfficeUtils;
import utils.StringUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws Exception {
File file = new File("temp" + File.separator + "androidtest" + File.separator + "test.xlsx");
XSSFWorkbook xssfSheets = OfficeUtils.openXlsx(file);
if (xssfSheets != null) {
XSSFSheet sheet1 = xssfSheets.getSheetAt(0);
List<AndroidTestInfo> testInfos = parseAllTestInfo(sheet1);
String s = generateTestCode(testInfos);
System.out.println(s);
}
}
private static String generateTestCode(List<AndroidTestInfo> testInfos) {
StringBuilder sb = new StringBuilder();
sb.append(StringUtils.formatSingleLine(1, "@Rule"));
sb.append(StringUtils.formatSingleLine(1, "public ActivityTestRule<XXXActivity> mActivityRule = new ActivityTestRule<>(XXXActivity.class, true, false);"));
sb.append("\n");
for (int i = 0; i < testInfos.size(); i++) {
AndroidTestInfo testInfo = testInfos.get(i);
List<AndroidTestAction> actions = testInfo.getActions();
AndroidTestAssertion assertion = testInfo.getAssertion();
String number = testInfo.getNumber().replace(".0", "");
if (number.equals("-1")) {
number = i + "";
}
String testMethodName = "test" + number;
sb.append(StringUtils.formatSingleLine(1, "/**"));
sb.append(StringUtils.formatSingleLine(1, " * " + testInfo.getTitle()));
sb.append(StringUtils.formatSingleLine(1, " */"));
sb.append(StringUtils.formatSingleLine(1, "@Test"));
sb.append(StringUtils.formatSingleLine(1, "public void " + testMethodName + "() throws InterruptedException {"));
sb.append(StringUtils.formatSingleLine(2, "Intent intent = new Intent();"));
sb.append(StringUtils.formatSingleLine(2, "mActivityRule.launchActivity(intent);"));
sb.append("\n");
sb.append(StringUtils.formatSingleLine(2, "// actions"));
for (AndroidTestAction action : actions) {
StringBuilder sbAction = new StringBuilder();
sbAction.append("onView(withContentDescription(\"" + action.getView() + "\"))");
switch (action.getActionType()) {
case AndroidTestAction.TYPE_TYPE_TEXT:
if(action.isNotAction()) {
sbAction.append("; // do nothing");
} else {
sbAction.append(".perform(typeText(\"" + action.getText() + "\"), closeSoftKeyboard());");
}
break;
case AndroidTestAction.TYPE_CLICK:
sbAction.append(".perform(click());");
break;
}
sb.append(StringUtils.formatSingleLine(2, sbAction.toString()));
}
sb.append("\n");
sb.append(StringUtils.formatSingleLine(2, "Thread.sleep(500);"));
sb.append("\n");
sb.append(StringUtils.formatSingleLine(2, "// assertions"));
switch (assertion.getAssertionType()) {
case AndroidTestAssertion.TYPE_SHOW_TOAST:
sb.append(StringUtils.formatSingleLine(2, "onView(withId(android.R.id.message))"));
sb.append(StringUtils.formatSingleLine(3, ".inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))"));
sb.append(StringUtils.formatSingleLine(3, ".check(matches(withText(\"" + assertion.getText() + "\")));"));
break;
default:
sb.append(StringUtils.formatSingleLine(2, "// TODO write your assertion~ or waiting seconds for check result by yourself"));
sb.append(StringUtils.formatSingleLine(2, "Thread.sleep(3000);"));
break;
}
sb.append(StringUtils.formatSingleLine(1, "}"));
sb.append("\n");
}
return sb.toString();
}
private static List<AndroidTestInfo> parseAllTestInfo(XSSFSheet sheet1) {
List<AndroidTestInfo> testInfos = new ArrayList<>();
for (int rowIndex = 0; rowIndex < sheet1.getPhysicalNumberOfRows(); rowIndex++) {
Row row = sheet1.getRow(rowIndex);
if (rowIndex == 0) {
parseHeaderInfo(row);
} else {
AndroidTestInfo testInfo = parseTestInfo(row);
testInfos.add(testInfo);
}
}
return testInfos;
}
private static AndroidTestInfo parseTestInfo(Row row) {
String num = getCellString(row.getCell(indexs.get(INDEX_NUMBER)));
String title = getCellString(row.getCell(indexs.get(INDEX_TITLE)));
String actions = getCellString(row.getCell(indexs.get(INDEX_ACTIONS)));
String assertion = getCellString(row.getCell(indexs.get(INDEX_ASSERTION)));
AndroidTestInfo testInfo = new AndroidTestInfo();
testInfo.setNumber(num);
testInfo.setTitle(title);
testInfo.setActions(parseActions(actions));
testInfo.setAssertion(parseAssertion(assertion));
return testInfo;
}
// 编号
private static final String INDEX_NUMBER = "number";
// 测试项
private static final String INDEX_TITLE = "title";
// 操作步骤
private static final String INDEX_ACTIONS = "actions";
// 预期结果
private static final String INDEX_ASSERTION = "assertion";
// 数据列索引信息
private static Map<String, Integer> indexs;
private static void parseHeaderInfo(Row row) {
indexs = new HashMap<>();
for (int cellIndex = 0; cellIndex < row.getPhysicalNumberOfCells(); cellIndex++) {
Cell cell = row.getCell(cellIndex);
String cellValue = getCellString(cell);
switch (cellValue) {
case "编号":
indexs.put(INDEX_NUMBER, cellIndex);
break;
case "测试项":
indexs.put(INDEX_TITLE, cellIndex);
break;
case "操作步骤":
indexs.put(INDEX_ACTIONS, cellIndex);
break;
case "预期结果":
indexs.put(INDEX_ASSERTION, cellIndex);
break;
}
}
}
private static List<AndroidTestAction> parseActions(String actionContent) {
List<AndroidTestAction> actions = new ArrayList<>();
Pattern pattern = Pattern.compile("([\\d]{1,2})、(【.*?】)(【.*?】)?(:[\\S]+[\\s]+)?");
Matcher matcher = pattern.matcher(actionContent);
while (matcher.find()) {
int step = -1;
if (matcher.group(1) != null) {
step = Integer.parseInt(matcher.group(1));
}
boolean isNotAction = false;
int actionType = -1;
String actionTypeContent = matcher.group(2);
if (actionTypeContent != null) {
if(actionTypeContent.startsWith("【不")) {
isNotAction = true;
actionTypeContent = actionTypeContent.replaceFirst("不", "");
}
switch (actionTypeContent) {
case "【输入】":
actionType = AndroidTestAction.TYPE_TYPE_TEXT;
break;
case "【点击】":
actionType = AndroidTestAction.TYPE_CLICK;
break;
}
}
String view = null;
if (matcher.group(3) != null) {
view = matcher.group(3).replace("【", "").replace("】", "");
}
String text = null;
if (matcher.group(4) != null) {
text = matcher.group(4).replaceFirst(":", "").trim();
}
AndroidTestAction action = new AndroidTestAction();
action.setStep(step);
action.setNotAction(isNotAction);
action.setActionType(actionType);
action.setView(view);
action.setText(text);
actions.add(action);
}
return actions;
}
private static AndroidTestAssertion parseAssertion(String assertionContent) {
Pattern pattern = Pattern.compile("(【.*?】)(:[\\S\\s]+)?");
Matcher matcher = pattern.matcher(assertionContent);
if (matcher.find()) {
int assertionType = -1;
if (matcher.group(1) != null) {
switch (matcher.group(1)) {
case "【提示】":
assertionType = AndroidTestAssertion.TYPE_SHOW_TOAST;
break;
case "【进入页面】":
assertionType = AndroidTestAssertion.TYPE_SHOW_ACTIVITY;
break;
}
}
String text = null;
if (matcher.group(2) != null) {
text = matcher.group(2).replaceFirst(":", "").trim();
}
AndroidTestAssertion assertion = new AndroidTestAssertion();
assertion.setAssertionType(assertionType);
assertion.setText(text);
return assertion;
}
return null;
}
private static String getCellString(Cell cell) {
String cellValue;
try {
cellValue = cell.getStringCellValue();
} catch (IllegalStateException e) {
cellValue = cell.getNumericCellValue() + "";
}
return cellValue;
}
}