Commit d25738da by leizuo

新增lemon项目-测试代码

parents
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## allure start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/.." >/dev/null
export APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="allure"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and ALLURE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/lib/allure-commandline-2.13.9.jar:$APP_HOME/lib/jcommander-1.78.jar:$APP_HOME/lib/allure-generator-2.13.9.jar:$APP_HOME/lib/allure-plugin-api-2.13.9.jar:$APP_HOME/lib/jackson-dataformat-xml-2.9.8.jar:$APP_HOME/lib/allure-model-2.13.0.jar:$APP_HOME/lib/jackson-module-jaxb-annotations-2.9.8.jar:$APP_HOME/lib/jackson-databind-2.9.8.jar:$APP_HOME/lib/jackson-dataformat-yaml-2.9.8.jar:$APP_HOME/lib/commons-io-2.6.jar:$APP_HOME/lib/jetty-server-9.4.20.v20190813.jar:$APP_HOME/lib/slf4j-log4j12-1.7.28.jar:$APP_HOME/lib/jackson-annotations-2.9.0.jar:$APP_HOME/lib/jackson-core-2.9.8.jar:$APP_HOME/lib/snakeyaml-1.23.jar:$APP_HOME/lib/javax.servlet-api-3.1.0.jar:$APP_HOME/lib/jetty-http-9.4.20.v20190813.jar:$APP_HOME/lib/jetty-io-9.4.20.v20190813.jar:$APP_HOME/lib/allure1-model-1.0.jar:$APP_HOME/lib/slf4j-api-1.7.28.jar:$APP_HOME/lib/log4j-1.2.17.jar:$APP_HOME/lib/jaxb-api-2.3.1.jar:$APP_HOME/lib/httpclient-4.5.9.jar:$APP_HOME/lib/tika-core-1.22.jar:$APP_HOME/lib/freemarker-2.3.29.jar:$APP_HOME/lib/jetty-util-9.4.20.v20190813.jar:$APP_HOME/lib/opencsv-4.6.jar:$APP_HOME/lib/flexmark-0.50.36.jar:$APP_HOME/lib/woodstox-core-5.0.3.jar:$APP_HOME/lib/stax2-api-3.1.4.jar:$APP_HOME/lib/javax.activation-api-1.2.0.jar:$APP_HOME/lib/properties-2.0.RC5.jar:$APP_HOME/lib/jaxb-utils-1.0.jar:$APP_HOME/lib/httpcore-4.4.11.jar:$APP_HOME/lib/commons-beanutils-1.9.3.jar:$APP_HOME/lib/commons-logging-1.2.jar:$APP_HOME/lib/commons-codec-1.11.jar:$APP_HOME/lib/commons-text-1.3.jar:$APP_HOME/lib/commons-lang3-3.9.jar:$APP_HOME/lib/commons-collections4-4.2.jar:$APP_HOME/lib/flexmark-util-0.50.36.jar:$APP_HOME/lib/commons-collections-3.2.2.jar:$APP_HOME/lib/config
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $ALLURE_OPTS -classpath "\"$CLASSPATH\"" io.qameta.allure.CommandLine "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem allure startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%..
@rem Add default JVM options here. You can also use JAVA_OPTS and ALLURE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\lib\allure-commandline-2.13.9.jar;%APP_HOME%\lib\jcommander-1.78.jar;%APP_HOME%\lib\allure-generator-2.13.9.jar;%APP_HOME%\lib\allure-plugin-api-2.13.9.jar;%APP_HOME%\lib\jackson-dataformat-xml-2.9.8.jar;%APP_HOME%\lib\allure-model-2.13.0.jar;%APP_HOME%\lib\jackson-module-jaxb-annotations-2.9.8.jar;%APP_HOME%\lib\jackson-databind-2.9.8.jar;%APP_HOME%\lib\jackson-dataformat-yaml-2.9.8.jar;%APP_HOME%\lib\commons-io-2.6.jar;%APP_HOME%\lib\jetty-server-9.4.20.v20190813.jar;%APP_HOME%\lib\slf4j-log4j12-1.7.28.jar;%APP_HOME%\lib\jackson-annotations-2.9.0.jar;%APP_HOME%\lib\jackson-core-2.9.8.jar;%APP_HOME%\lib\snakeyaml-1.23.jar;%APP_HOME%\lib\javax.servlet-api-3.1.0.jar;%APP_HOME%\lib\jetty-http-9.4.20.v20190813.jar;%APP_HOME%\lib\jetty-io-9.4.20.v20190813.jar;%APP_HOME%\lib\allure1-model-1.0.jar;%APP_HOME%\lib\slf4j-api-1.7.28.jar;%APP_HOME%\lib\log4j-1.2.17.jar;%APP_HOME%\lib\jaxb-api-2.3.1.jar;%APP_HOME%\lib\httpclient-4.5.9.jar;%APP_HOME%\lib\tika-core-1.22.jar;%APP_HOME%\lib\freemarker-2.3.29.jar;%APP_HOME%\lib\jetty-util-9.4.20.v20190813.jar;%APP_HOME%\lib\opencsv-4.6.jar;%APP_HOME%\lib\flexmark-0.50.36.jar;%APP_HOME%\lib\woodstox-core-5.0.3.jar;%APP_HOME%\lib\stax2-api-3.1.4.jar;%APP_HOME%\lib\javax.activation-api-1.2.0.jar;%APP_HOME%\lib\properties-2.0.RC5.jar;%APP_HOME%\lib\jaxb-utils-1.0.jar;%APP_HOME%\lib\httpcore-4.4.11.jar;%APP_HOME%\lib\commons-beanutils-1.9.3.jar;%APP_HOME%\lib\commons-logging-1.2.jar;%APP_HOME%\lib\commons-codec-1.11.jar;%APP_HOME%\lib\commons-text-1.3.jar;%APP_HOME%\lib\commons-lang3-3.9.jar;%APP_HOME%\lib\commons-collections4-4.2.jar;%APP_HOME%\lib\flexmark-util-0.50.36.jar;%APP_HOME%\lib\commons-collections-3.2.2.jar;%APP_HOME%\lib\config
@rem Execute allure
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %ALLURE_OPTS% -classpath "%CLASSPATH%" io.qameta.allure.CommandLine %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable ALLURE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%ALLURE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
plugins:
- junit-plugin
- packages-plugin
plugins:
- junit-xml-plugin
- xunit-xml-plugin
- trx-plugin
- behaviors-plugin
- packages-plugin
- screen-diff-plugin
- xctest-plugin
- jira-plugin
- xray-plugin
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.LoggerLog
org.eclipse.jetty.LEVEL=WARN
\ No newline at end of file
log4j.rootLogger=INFO, stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%m%n
log4j.logger.org.mortbay.log = INFO
\ No newline at end of file
The directory with Allure plugins. To add the plugin simply unpack it to this folder.
\ No newline at end of file
id: behaviors
name: Behaviors aggregator
description: The aggregator adds behaviors tab to the report
extensions:
- io.qameta.allure.behaviors.BehaviorsPlugin
jsFiles:
- index.js
\ No newline at end of file
'use strict';
allure.api.addTranslation('en', {
tab: {
behaviors: {
name: 'Behaviors'
}
},
widget: {
behaviors: {
name: 'Features by stories',
showAll: 'show all'
}
}
});
allure.api.addTranslation('ru', {
tab: {
behaviors: {
name: 'Функциональность'
}
},
widget: {
behaviors: {
name: 'Функциональность',
showAll: 'показать все'
}
}
});
allure.api.addTranslation('zh', {
tab: {
behaviors: {
name: '功能'
}
},
widget: {
behaviors: {
name: '特性场景',
showAll: '显示所有'
}
}
});
allure.api.addTranslation('de', {
tab: {
behaviors: {
name: 'Verhalten'
}
},
widget: {
behaviors: {
name: 'Features nach Stories',
showAll: 'Zeige alle'
}
}
});
allure.api.addTranslation('nl', {
tab: {
behaviors: {
name: 'Functionaliteit'
}
},
widget: {
behaviors: {
name: 'Features en story’s',
showAll: 'Toon alle'
}
}
});
allure.api.addTranslation('he', {
tab: {
behaviors: {
name: 'התנהגויות'
}
},
widget: {
behaviors: {
name: 'תכונות לפי סיפורי משתמש',
showAll: 'הצג הכול'
}
}
});
allure.api.addTranslation('br', {
tab: {
behaviors: {
name: 'Comportamentos'
}
},
widget: {
behaviors: {
name: 'Funcionalidades por história',
showAll: 'Mostrar tudo'
}
}
});
allure.api.addTranslation('ja', {
tab: {
behaviors: {
name: '振る舞い'
}
},
widget: {
behaviors: {
name: 'ストーリー別の機能',
showAll: '全て表示'
}
}
});
allure.api.addTranslation('es', {
tab: {
behaviors: {
name: 'Funcionalidades'
}
},
widget: {
behaviors: {
name: 'Funcionalidades por Historias de Usuario',
showAll: 'mostrar todo'
}
}
});
allure.api.addTranslation('kr', {
tab: {
behaviors: {
name: '동작'
}
},
widget: {
behaviors: {
name: '스토리별 기능',
showAll: '전체 보기'
}
}
});
allure.api.addTranslation('fr', {
tab: {
behaviors: {
name: 'Comportements'
}
},
widget: {
behaviors: {
name: 'Thèmes par histoires',
showAll: 'Montrer tout'
}
}
});
allure.api.addTab('behaviors', {
title: 'tab.behaviors.name', icon: 'fa fa-list',
route: 'behaviors(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)',
onEnter: (function (testGroup, testResult, testResultTab) {
return new allure.components.TreeLayout({
testGroup: testGroup,
testResult: testResult,
testResultTab: testResultTab,
tabName: 'tab.behaviors.name',
baseUrl: 'behaviors',
url: 'data/behaviors.json',
csvUrl: 'data/behaviors.csv'
});
})
});
allure.api.addWidget('widgets', 'behaviors', allure.components.WidgetStatusView.extend({
rowTag: 'a',
title: 'widget.behaviors.name',
baseUrl: 'behaviors',
showLinks: true
}));
id: custom-logo
name: Custom logo aggregator
description: The aggregator replaces default Allure logo with a custom one
cssFiles:
- styles.css
\ No newline at end of file
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 128 128" version="1.1" viewBox="0 0 128 128" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_1"><rect fill="#F4F5F5" height="1520" opacity="0" width="727.938" x="-59.984" y="-351"/></g><g id="Layer_2"><g><circle cx="64" cy="64" fill="#6E9583" r="64"/><g><defs><circle cx="64" cy="64" id="SVGID_3_" r="64"/></defs><clipPath id="SVGID_2_"><use overflow="visible" xlink:href="#SVGID_3_"/></clipPath><polygon clip-path="url(#SVGID_2_)" fill="#648778" points="93.572,29.677 128,64 128,128 54.36,128 33.341,106.906 "/></g><path d="M84.044,20H36.018C33.579,20,32,22.11,32,24.549v78.903c0,2.439,1.579,4.549,4.018,4.549h55.989 c2.439,0,4.018-2.11,4.018-4.549V32.143L84.044,20z" fill="#F1F1F1"/><g><defs><path d="M84.044,20H36.018C33.579,20,32,22.11,32,24.549v78.903c0,2.439,1.579,4.549,4.018,4.549h55.989 c2.439,0,4.018-2.11,4.018-4.549V32.143L84.044,20z" id="SVGID_5_"/></defs><clipPath id="SVGID_4_"><use overflow="visible" xlink:href="#SVGID_5_"/></clipPath><g clip-path="url(#SVGID_4_)"><polygon fill="#DDE1F1" points="50.948,67.621 65.539,82.042 42.971,83.087 49.777,90 42.971,91.087 49.277,97.555 42.971,99.087 53.027,109.305 97.684,109.305 97.684,75.707 97.075,54.055 81.059,37.758 70.97,44.918 62.684,35.107 "/></g></g><path d="M88.186,32.138l7.839,0.005L84.044,20v7.96C84.044,30.398,85.769,32.138,88.186,32.138z" fill="#C2DFC9"/><path d="M84,83.5H44c-0.828,0-1.5-0.672-1.5-1.5s0.672-1.5,1.5-1.5h40c0.828,0,1.5,0.672,1.5,1.5 S84.828,83.5,84,83.5z" fill="#495260"/><path d="M84,91.5H44c-0.828,0-1.5-0.672-1.5-1.5s0.672-1.5,1.5-1.5h40c0.828,0,1.5,0.672,1.5,1.5 S84.828,91.5,84,91.5z" fill="#495260"/><path d="M84,99.5H44c-0.828,0-1.5-0.672-1.5-1.5s0.672-1.5,1.5-1.5h40c0.828,0,1.5,0.672,1.5,1.5 S84.828,99.5,84,99.5z" fill="#495260"/><g><path d="M69.568,31.844l-1.319,11.303c2.314,0.88,4.242,2.728,5.132,5.245c0.573,1.619,0.631,3.292,0.274,4.851 l10.257,4.895c0.527,0.252,1.155-0.023,1.329-0.581c1.308-4.188,1.323-8.819-0.253-13.273 c-2.379-6.723-7.827-11.477-14.212-13.254C70.21,30.872,69.636,31.26,69.568,31.844z" fill="#0E9CD9"/><path d="M66.68,59.901c-3.653,0.668-7.398-1.12-9.176-4.38c-1.094-2.006-1.312-4.174-0.858-6.157L46.39,44.469 c-0.527-0.251-1.155,0.023-1.329,0.58c-1.286,4.118-1.322,8.663,0.175,13.049c3.701,10.842,15.624,16.783,26.503,13.191 c4.655-1.537,8.399-4.531,10.911-8.3c0.324-0.486,0.141-1.147-0.385-1.398l-10.257-4.896 C70.751,58.296,68.929,59.49,66.68,59.901z" fill="#E95037"/><path d="M62.239,43.074c0.734-0.26,1.479-0.405,2.22-0.464l1.316-11.275c0.067-0.576-0.389-1.08-0.968-1.071 c-2.218,0.035-4.469,0.421-6.676,1.202c-4.455,1.576-8.045,4.5-10.479,8.151c-0.324,0.486-0.142,1.147,0.385,1.399l10.257,4.895 C59.282,44.654,60.62,43.647,62.239,43.074z" fill="#69B32D"/><g><defs><path d="M69.695,30.76l-1.446,12.387c2.314,0.88,4.242,2.728,5.132,5.245c0.573,1.619,0.631,3.292,0.274,4.851 l10.257,4.895c0.527,0.252,1.155-0.023,1.329-0.581c1.308-4.188,1.323-8.819-0.253-13.273 C82.476,37.185,76.541,32.281,69.695,30.76z M66.68,59.901c-3.653,0.668-7.398-1.12-9.176-4.38 c-1.094-2.006-1.312-4.174-0.858-6.157L46.39,44.469c-0.527-0.251-1.155,0.023-1.329,0.58 c-1.286,4.118-1.322,8.663,0.175,13.049c3.701,10.842,15.624,16.783,26.503,13.191c4.655-1.537,8.399-4.531,10.911-8.3 c0.324-0.486,0.141-1.147-0.385-1.398l-10.257-4.896C70.751,58.296,68.929,59.49,66.68,59.901z M62.239,43.074 c0.734-0.26,1.479-0.405,2.22-0.464l1.316-11.275c0.067-0.576-0.389-1.08-0.968-1.071c-2.218,0.035-4.469,0.421-6.676,1.202 c-4.455,1.576-8.045,4.5-10.479,8.151c-0.324,0.486-0.142,1.147,0.385,1.399l10.257,4.895 C59.282,44.654,60.62,43.647,62.239,43.074z" id="SVGID_7_"/></defs><clipPath id="SVGID_6_"><use overflow="visible" xlink:href="#SVGID_7_"/></clipPath><circle clip-path="url(#SVGID_6_)" cx="65.151" cy="51.304" fill="#FFFFFF" opacity="0.4" r="12.507"/></g></g></g></g></svg>
\ No newline at end of file
.side-nav__brand {
background: url('custom-logo.svg') no-repeat left center !important;
margin-left: 10px;
}
\ No newline at end of file
id: jira
name: Jira Plugin
description: The plugin that adds support for Jira integration.
extensions:
- io.qameta.allure.jira.JiraExportPlugin
id: junit
name: JUnit Plugin
description: The plugin that adds support for results in JUnit.xml data format.
extensions:
- io.qameta.allure.junitxml.JunitXmlPlugin
\ No newline at end of file
id: packages
name: Packages aggregator
description: The aggregator adds packages tab to the report
extensions:
- io.qameta.allure.packages.PackagesPlugin
jsFiles:
- index.js
\ No newline at end of file
'use strict';
allure.api.addTranslation('en', {
tab: {
packages: {
name: 'Packages'
}
}
});
allure.api.addTranslation('ru', {
tab: {
packages: {
name: 'Пакеты'
}
}
});
allure.api.addTranslation('zh', {
tab: {
packages: {
name: '包'
}
}
});
allure.api.addTranslation('de', {
tab: {
packages: {
name: 'Pakete'
}
}
});
allure.api.addTranslation('nl', {
tab: {
packages: {
name: 'Packages'
}
}
});
allure.api.addTranslation('he', {
tab: {
packages: {
name: 'חבילות'
}
}
});
allure.api.addTranslation('br', {
tab: {
packages: {
name: 'Pacotes'
}
}
});
allure.api.addTranslation('ja', {
tab: {
packages: {
name: 'パッケージ'
}
}
});
allure.api.addTranslation('es', {
tab: {
packages: {
name: 'Paquetes'
}
}
});
allure.api.addTranslation('kr', {
tab: {
packages: {
name: '패키지'
}
}
});
allure.api.addTranslation('fr', {
tab: {
packages: {
name: 'Paquets'
}
}
});
allure.api.addTab('packages', {
title: 'tab.packages.name', icon: 'fa fa-align-left',
route: 'packages(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)',
onEnter: (function (testGroup, testResult, testResultTab) {
return new allure.components.TreeLayout({
testGroup: testGroup,
testResult: testResult,
testResultTab: testResultTab,
tabName: 'tab.packages.name',
baseUrl: 'packages',
url: 'data/packages.json'
});
})
});
id: screen-diff
name: Screen diff
description: Who cares about description by just-boris
jsFiles:
- index.js
cssFiles:
- styles.css
\ No newline at end of file
(function () {
var settings = allure.getPluginSettings('screen-diff', { diffType: 'diff' });
function renderImage(src) {
return (
'<div class="screen-diff__container">' +
'<img class="screen-diff__image" src="' +
src +
'">' +
'</div>'
);
}
function findImage(data, name) {
if (data.testStage && data.testStage.attachments) {
var matchedImage = data.testStage.attachments.filter(function (attachment) {
return attachment.name === name;
})[0];
if (matchedImage) {
return 'data/attachments/' + matchedImage.source;
}
}
return null;
}
function renderDiffContent(type, diffImage, actualImage, expectedImage) {
if (type === 'diff') {
if (diffImage) {
return renderImage(diffImage);
}
}
if (type === 'overlay' && expectedImage) {
return (
'<div class="screen-diff__overlay screen-diff__container">' +
'<img class="screen-diff__image" src="' +
expectedImage +
'">' +
'<div class="screen-diff__image-over">' +
'<img class="screen-diff__image" src="' +
actualImage +
'">' +
'</div>' +
'</div>'
);
}
if (actualImage) {
return renderImage(actualImage);
}
return 'No diff data provided';
}
var TestResultView = Backbone.Marionette.View.extend({
regions: {
subView: '.screen-diff-view',
},
template: function () {
return '<div class="screen-diff-view"></div>';
},
onRender: function () {
var data = this.model.toJSON();
var testType = data.labels.filter(function (label) {
return label.name === 'testType';
})[0];
var diffImage = findImage(data, 'diff');
var actualImage = findImage(data, 'actual');
var expectedImage = findImage(data, 'expected');
if (!testType || testType.value !== 'screenshotDiff') {
return;
}
this.showChildView(
'subView',
new ScreenDiffView({
diffImage: diffImage,
actualImage: actualImage,
expectedImage: expectedImage,
}),
);
},
});
var ErrorView = Backbone.Marionette.View.extend({
templateContext: function () {
return this.options;
},
template: function (data) {
return '<pre class="screen-diff-error">' + data.error + '</pre>';
},
});
var AttachmentView = Backbone.Marionette.View.extend({
regions: {
subView: '.screen-diff-view',
},
template: function () {
return '<div class="screen-diff-view"></div>';
},
onRender: function () {
jQuery
.getJSON(this.options.sourceUrl)
.then(this.renderScreenDiffView.bind(this), this.renderErrorView.bind(this));
},
renderErrorView: function (error) {
console.log(error);
this.showChildView(
'subView',
new ErrorView({
error: error.statusText,
}),
);
},
renderScreenDiffView: function (data) {
this.showChildView(
'subView',
new ScreenDiffView({
diffImage: data.diff,
actualImage: data.actual,
expectedImage: data.expected,
}),
);
},
});
var ScreenDiffView = Backbone.Marionette.View.extend({
className: 'pane__section',
events: function () {
return {
['click [name="screen-diff-type-' + this.cid + '"]']: 'onDiffTypeChange',
'mousemove .screen-diff__overlay': 'onOverlayMove',
};
},
initialize: function (options) {
this.diffImage = options.diffImage;
this.actualImage = options.actualImage;
this.expectedImage = options.expectedImage;
this.radioName = 'screen-diff-type-' + this.cid;
},
templateContext: function () {
return {
diffType: settings.get('diffType'),
diffImage: this.diffImage,
actualImage: this.actualImage,
expectedImage: this.expectedImage,
radioName: this.radioName,
};
},
template: function (data) {
if (!data.diffImage && !data.actualImage && !data.expectedImage) {
return '';
}
return (
'<h3 class="pane__section-title">Screen Diff</h3>' +
'<div class="screen-diff__content">' +
'<div class="screen-diff__switchers">' +
'<label><input type="radio" name="' +
data.radioName +
'" value="diff"> Show diff</label>' +
'<label><input type="radio" name="' +
data.radioName +
'" value="overlay"> Show overlay</label>' +
'</div>' +
renderDiffContent(
data.diffType,
data.diffImage,
data.actualImage,
data.expectedImage,
) +
'</div>'
);
},
adjustImageSize: function (event) {
var overImage = this.$(event.target);
overImage.width(overImage.width());
},
onRender: function () {
const diffType = settings.get('diffType');
this.$('[name="' + this.radioName + '"][value="' + diffType + '"]').prop(
'checked',
true,
);
if (diffType === 'overlay') {
this.$('.screen-diff__image-over img').on('load', this.adjustImageSize.bind(this));
}
},
onOverlayMove: function (event) {
var pageX = event.pageX;
var containerScroll = this.$('.screen-diff__container').scrollLeft();
var elementX = event.currentTarget.getBoundingClientRect().left;
var delta = pageX - elementX + containerScroll;
this.$('.screen-diff__image-over').width(delta);
},
onDiffTypeChange: function (event) {
settings.save('diffType', event.target.value);
this.render();
},
});
allure.api.addTestResultBlock(TestResultView, { position: 'before' });
allure.api.addAttachmentViewer('application/vnd.allure.image.diff', {
View: AttachmentView,
icon: 'fa fa-exchange',
});
})();
.screen-diff__switchers {
margin-bottom: 1em;
}
.screen-diff__switchers label + label {
margin-left: 1em;
}
.screen-diff__overlay {
position: relative;
cursor: col-resize;
}
.screen-diff__container {
overflow-x: auto;
}
.screen-diff__image-over {
top: 0;
left: 0;
bottom: 0;
background: #fff;
position: absolute;
overflow: hidden;
box-shadow: 2px 0 1px -1px #aaa;
}
.screen-diff-error {
color: #fd5a3e;
}
id: trx
name: XUnit TRX Plugin
description: The plugin that adds support for results TRX data format.
extensions:
- io.qameta.allure.trx.TrxPlugin
\ No newline at end of file
id: xctest
name: XCTest Plugin
description: The plugin that adds support for results XCTest data format.
extensions:
- io.qameta.allure.xctest.XcTestPlugin
\ No newline at end of file
id: xray
name: Xray Plugin
description: The plugin that adds support for Xray integration.
extensions:
- io.qameta.allure.xray.XrayTestRunExportPlugin
id: xunit-xml
name: XUnit XML v2 Plugin
description: The plugin that adds support for results in Xunit.net xml data format.
extensions:
- io.qameta.allure.xunitxml.XunitXmlPlugin
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Lemon" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="18" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lemon</groupId>
<artifactId>Lemon</artifactId>
<version>1.0-SNAPSHOT</version>
<!--公共配置-->
<properties>
<maven.compiler.source>18</maven.compiler.source>
<maven.compiler.target>18</maven.compiler.target>
<!--文件拷贝时的编码-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 编译时的编码-->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<!--Maven坐标-->
<aspectj.version>1.9.2</aspectj.version>
</properties>
<!-- maven-surefire-plugin 配合testng执行测试用例的maven插件 -->
<!--java:io.qameta.allure:allure-java-commons-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<!-- 测试失败后,是否忽略并继续测试 -->
<testFailureIgnore>true</testFailureIgnore>
<suiteXmlFiles>
<!-- testng配置文件名称 -->
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<!--设置参数命令行 -->
<argLine>
<!-- UTF-8编码 -->
-Dfile.encoding=UTF-8
<!-- 配置拦截器 -->
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<systemProperties>
<property>
<!-- 配置 allure 结果存储路径 -->
<name>allure.results.directory</name>
<value>${project.build.directory}/allure-results</value>
</property>
</systemProperties>
</configuration>
<dependencies>
<!-- aspectjweaver maven坐标 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<!-- JSON类型操作坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<!-- 对office软件读写功能 -->
<!-- <dependency>-->
<!-- <groupId>org.apache.poi</groupId>-->
<!-- <artifactId>poi-ooxml</artifactId>-->
<!-- <version>3.17</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!--EasyPoi特点:设计精巧,使用简单-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.0.0</version>
</dependency>
<!--xml文件 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<!--testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<!--Excel列进行验证-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<!--api -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
<!--MySQL数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!--数据库连接包的工具dbutils-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--oracle数据库驱动-->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!--log日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- allure2 maven坐标 -->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>2.17.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.lemon.cases;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.lemon.pojo.API;
import com.lemon.pojo.Case;
import com.lemon.pojo.JsonPathVaildate;
import com.lemon.pojo.WriteBackData;
import com.lemon.utils.AuthorizationUtils;
import com.lemon.utils.ExcelUtils;
import com.lemon.utils.HttpUtils;
import io.qameta.allure.Step;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import java.io.FileInputStream;
import java.util.List;
import java.util.Properties;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-26 22:09
**/
public class BaseCase {
// 日志
public static Logger log = Logger.getLogger(BaseCase.class);
/**
* 添加Excel回写对象到回写集合中
*
* @param rowNum:回写行
* @param cellNum:回写列
* @param body:回写内容
*/
@Step("添加回写内容")
public void addWBD(int rowNum, int cellNum, String body) {
//创建回写内容
WriteBackData wbd = new WriteBackData(rowNum, cellNum, body);
ExcelUtils.wbdList.add(wbd);
}
/**
* 调用接口方法
*
* @param api:接口信息对象,包含Excel中sheet页信息
* @param cas:用例信息对象,需要接口请求参数
* @param isAuthorization:接口是否需要传递token值进行请求
* @return
*/
@Step("接口调用方法")
public String call(API api, Case cas, boolean isAuthorization) {
log.info("====================================调用接口:" + api.getName() + "====================================");
String url = api.getUrl();
String type = api.getMethod();
String contentType = api.getContentType();
String params = cas.getParams();
String body = HttpUtils.call(url, type, params, contentType, isAuthorization);
return body;
}
/*
* 接口响应内容断言
* @param cas
* @param body
*/
@Step("响应结果进行断言")
public Boolean assertResponse(Case cas, String body) {
// 定义断言是否成功
boolean flag = false;
// 获取预期结果
String expectValue = cas.getExpectValue();
// 调用parse方法解析JSON
Object jsonObj = JSONObject.parse(expectValue);
// 如果Case中expectValue是数组类型的JSON格式,那么采用多字段匹配断言逻辑。
if (jsonObj instanceof JSONArray) { // 判断jsonObj是否是JSONArray的对象
// 所有JSON数据转换为集合
List<JsonPathVaildate> list = JSONObject.parseArray(expectValue, JsonPathVaildate.class);
//循环,多关键字段匹配断言
for (JsonPathVaildate jpv : list) {
//一个断言表达式
String expression = jpv.getExpression();
//表达式期望值
String value = jpv.getValue();
//对响应结果进行一个JSONPath,寻找实际的值
String actualValue = JSONPath.read(body, expression) == null ? "" : JSONPath.read(body, expression).toString();
//期望值和实际值进行断言
flag = value.equals(actualValue);
//期望值和实际值进行断言
System.out.println("实际值:" + actualValue + ",预期值:" + value + "断言结果" + value.equals(actualValue));
//判断所有匹配字段是否为true
if (flag == false) {
//说明断言失败
break;
}
}
//如果Case中expectValue不是数组类型的JSON格式,那么采用等值匹配。
} else if (jsonObj instanceof JSONObject) {
flag = body.equals(expectValue);
}
return flag;
}
/**
* 参数化替换方法
*
* @param source:被替换的字符串(params或者sql中包含${xxx})
* @return
*/
@Step("参数化替换")
public String replace(String source) {
//判断如果传入的字符串为空,直接返回
if (StringUtils.isBlank(source)) {
return source;
}
//遍历环境变量,取出所有的oldStr和newStr
for (String oldStr : AuthorizationUtils.env.keySet()) {
//判断source中是否包含oldStr,如果包含就替换newStr
String newStr = AuthorizationUtils.env.get(oldStr);
source = source.replace(oldStr, newStr);
}
return source;
}
/**
* 在初始化方法中,加载参数化内容,并且存储到env环境变量中
*
* @throws Exception
*/
@BeforeSuite
@Step("初始化")
public void init() throws Exception {
log.info("========================项目启动========================");
//从params.properties文件中读取参数化内容
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("src/test/resources/paramas.properties");
prop.load(fis);
//把params.properties文件读取的内容存储到env环境变量中
for (Object key : prop.keySet()) {
Object value = prop.get(key);
//put(String oldStr,String newStr)
if (key.toString().contains("registerMobilePhone")) {
AuthorizationUtils.env.put(key.toString(), value.toString());
} else {
AuthorizationUtils.env.put(key.toString(), value.toString());
}
}
}
/**
* 套件执行完毕之后的操作
*/
@AfterSuite
@Step("结束")
public void finish() {
//所有的接口都执行完毕后再执行批量回写
log.info("=======================批量回写=======================");
ExcelUtils.batchWrite();
log.info("=======================项目结束=======================");
}
/*
* 1、allure
* Maven常用命令:
* test:执行test文件夹中所有代码
* package:把当前项目打包(会生成test)
* clean:清空当前项目下的Maven生产的文件
* install:把jar包安装到本地仓库(会执行test、package)
*
* 1、导入allure坐标
* 2、导入surefire插件
* 3、运行clean test(生成报表数据)
* 4、运行io.qameta.allure:allure-maven:server 启动报表服务器
* 5、如果你需要加上一些文字说明
* (1)@Test(dataProvider = "datas1",description = "充值测试") // DTO数据传输
* (2)@Step("回写Excel") 详细描写自动化程序的每个执行步骤
* //其他注释:
* Features:标注主要功能模块
* Stories:标注Features功能模块下的分支功能
* Title:标注Stories下的测试用例名称
* Severity:标注测试用例的重要级别
* Description:标注测试用例的描述
*
* 2、mock-server
* 当接口尚未开发完毕,创建一个虚拟接口,继续测试;
* https://github.com/dreamhead/moco
* https://github.com/dreamhead/moco/blob/master/moco-doc/apis.md
*
* 3、Jenkins
* 持续抓取版本库最新代码,定时构建(执行代码),生成对应构建信息,发送邮件,生生报表。
*
*/
public static void main(String[] args) {
}
}
package com.lemon.cases;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPatch;
import com.alibaba.fastjson.JSONPath;
import com.lemon.constants.Constants;
import com.lemon.pojo.API;
import com.lemon.pojo.Case;
import com.lemon.pojo.JsonPathVaildate;
import com.lemon.pojo.WriteBackData;
import com.lemon.utils.AuthorizationUtils;
import com.lemon.utils.ExcelUtils;
import com.lemon.utils.HttpUtils;
import com.lemon.utils.SqlUtils;
import io.qameta.allure.Description;
import org.testng.Assert;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.List;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 13:57
**/
public class LoginCase extends BaseCase {
@Test(dataProvider = "datas1",description = "登录测试") // DTO数据传输
@Description("登录...xxx.xxx")
public void testLogin(API api, Case cas) throws Exception {
//1、参数化替换
String params = replace(cas.getParams());
String sql = replace(cas.getCheckSQL());
cas.setParams(params);
cas.setCheckSQL(sql);
//2、数据库前置查询结果(断言必须在接口执行前后都查询)
Object beforeSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//3、调用接口
String body = call(api, cas, false);
// 3.1 将登录的token存储(仅限于登录接口特有)
AuthorizationUtils.storeToken(body);
//4、断言响应结果,Excel中预期响应数据与实际响应数据进行对比
Boolean assertResponseFlag = assertResponse(cas, body);
//5、添加接口响应回写excel内容
addWBD(Integer.parseInt(cas.getId()), Constants.ACTURL_WRITER_BACK_CELL_NUM, body);
//6、数据库后置查询结果
Object afterSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//7、数据库断言
//8、添加断言回写内容
//9、添加日志
//10、报表断言
}
// 使用对应参数编写接口自动化
@DataProvider(name = "datas0")
public Object[][] datas0() {
//Object[m][n] m代表执行次数,n代表参数个数
Object[][] datas = {
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110011\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110012\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110013\",\"pwd\":\"123456\"}"},
};
return datas;
}
// 使用Excel文件传输接口信息和请求信息
@DataProvider(name = "datas1")
public Object[][] datas1() {
// 传参apiID
Object[][] datas = ExcelUtils.getAPIAndCaseByApiId("2");
return datas;
}
/*
* 鉴权:token、cookie、session
* 1、cookie:客户端(浏览器)本地缓存==>存在磁盘本地某个路径
* 存储一些小的明文信息,不会放非常隐秘的信息
* cookie是如何生成的?客户端(JS脚本)和服务端(Java、Python)都能生成,一般都是服务器生成。
*
* NAME=VALUE 赋予cookie的名称和其值(必填项)
* expires=DATE cookie的有效期(被max-age取代)
* path=PATH cookie适用路径,默认为当前路径
* domain=域名 cookie适用域名,默认当前域名
* max-age 用秒来设置cookie生存期
* size 大小
* HttpOnly 只有在http请求头中会带cookie信息,禁止通过JS访问
* secure 设置是否只能通过HTTPS来传递此条cookie
*
* 2、session:服务端缓存==>存储在内存中或者数据库中,断开了连接(关闭浏览器)session就会失效。
* 默认失效时间为30分钟。优点:可以存储任意信息,缺点:耗内存;
* session是如何生成的?服务端生成,使用cookie回写到客户端(jsessionId),客户端每次发送请求时自动携带该cookie(jsessionId)。
*
* 3、token:票据==>存储在客户端(浏览器)对header或body中
* 优点:不存储在服务端。一般只用来做鉴权存储用户相关信息。
* token是如何生成的?服务端生成,携带在header或body中回写客户端,客户端以同样的方法传递给服务端。
*
* 4、如何实现鉴权
* a、获取到对应的jsession或者对应token字符串;
* b、在请求的同时添加上它们;
* token子验证过程:结果是相等的,算法是相同的。
*
* 5、代码鉴权逻辑:
* a、在获取Post请求响应之后(HttpUtils),判断响应体中是否还有token字符;
* b、如果含有token存储到env环境变量中,(Map<String,String>)
* c、每次post、get、patch请求之前,调用添加token的方法addToken
* d、addToken中会判断env环境中是否有Token,如果有添加到对应的请求头中
* */
}
package com.lemon.cases;
import com.alibaba.fastjson.JSONPath;
import com.lemon.constants.Constants;
import com.lemon.pojo.API;
import com.lemon.pojo.Case;
import com.lemon.utils.AuthorizationUtils;
import com.lemon.utils.ExcelUtils;
import com.lemon.utils.HttpUtils;
import com.lemon.utils.SqlUtils;
import io.qameta.allure.Step;
import org.apache.commons.lang3.StringUtils;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 13:57
**/
public class RechargeCase extends BaseCase {
@Test(dataProvider = "datas1", description = "充值测试") // DTO数据传输
public void testRecharge(API api, Case cas) throws Exception {
//1、参数化替换
String params = replace(cas.getParams());
String sql = replace(cas.getCheckSQL());
cas.setParams(params);
cas.setCheckSQL(sql);
//2、数据库前置查询结果(断言必须在接口执行前后都查询)
Object beforeSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//3、调用接口
String body = call(api, cas, true);
//4、断言响应结果,Excel中预期响应数据与实际响应数据进行对比
Boolean assertResponseFlag = assertResponse(cas, body);
//5、添加接口响应回写excel内容
addWBD(Integer.parseInt(cas.getId()), Constants.ACTURL_WRITER_BACK_CELL_NUM, body);
//6、数据库后置查询结果
Object afterSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//7、数据库断言
boolean sqlFlag = sqlAssert(cas, beforeSqlResult, afterSqlResult);
System.out.println("数据库断言结果:" + sqlFlag);
//8、添加断言回写内容
String assertContent = (assertResponseFlag && sqlFlag) ? "Pass" : "Fail";
addWBD(Integer.parseInt(cas.getId()), Constants.ASSERT_RESULT_CELL_NUM, assertContent);
//9、添加日志
//10、报表断言
}
/**
* 接口执行之后的sql结果-接口之前之前的sql结果=参数的amount金额
*
* @param cas
* @param beforeSqlResult
* @param afterSqlResult
* @return
*/
@Step("数据库断言,对比充值前后金额")
public boolean sqlAssert(Case cas, Object beforeSqlResult, Object afterSqlResult) {
String sql = cas.getCheckSQL();
//如果sql为空,说明不需要数据库断言
if (StringUtils.isBlank(sql)) {
return true;
} else {
//注册断言逻辑:前置sql结果为0,后置sql结果为1,其他情况断言失败
double aValue = Double.parseDouble(afterSqlResult.toString());
double bValue = Double.parseDouble(beforeSqlResult.toString());
// 从Excel的某条Case的JSON里获取amount字段
double amount = Double.parseDouble(JSONPath.read(cas.getParams(), "$.amount").toString());
// 操作金钱相关数据类型,使用BigDecimal类型
DecimalFormat df = new DecimalFormat("#.##");// 保留两位小数
BigDecimal d1 = new BigDecimal(aValue);
d1.setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal d2 = new BigDecimal(bValue);
d2.setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal d3 = new BigDecimal(amount);
d3 = d3.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("充值前的账户余额bValue:" + bValue);
System.out.println("充值后的账户余额aValue:" + aValue);
System.out.println("充值金额amount:" + amount);
System.out.println("相减:" + d1.subtract(d2));
if (d1.subtract(d2).equals(d3)) {
return true;
} else {
return false;
}
}
}
@DataProvider(name = "datas0")
public Object[][] datas0() {
//Object[m][n] m代表执行次数,n代表参数个数
Object[][] datas = {
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110011\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110012\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110013\",\"pwd\":\"123456\"}"},
};
return datas;
}
@DataProvider(name = "datas1")
public Object[][] datas1() {
// 传参apiID
Object[][] datas = ExcelUtils.getAPIAndCaseByApiId("3");
return datas;
}
}
package com.lemon.cases;
import com.alibaba.fastjson.JSONObject;
import com.lemon.constants.Constants;
import com.lemon.pojo.API;
import com.lemon.pojo.Case;
import com.lemon.utils.AuthorizationUtils;
import com.lemon.utils.ExcelUtils;
import com.lemon.utils.HttpUtils;
import com.lemon.utils.SqlUtils;
import netscape.javascript.JSObject;
import org.apache.commons.lang3.StringUtils;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 13:57
**/
public class RegisterCase extends BaseCase {
@Test(dataProvider = "datas1") // DTO数据传输
public void testRegister(API api, Case cas) throws Exception {
//1、参数化替换
String params = replace(cas.getParams());
String sql = replace(cas.getCheckSQL());
cas.setParams(params);
cas.setCheckSQL(sql);
//2、数据库前置查询结果(断言必须在接口执行前后都查询)
Object beforeSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//3、调用接口
String body = call(api, cas, false);
//4、断言响应结果,Excel中预期响应数据与实际响应数据进行对比
Boolean assertResponseFlag = assertResponse(cas, body);
//5、添加接口响应回写excel内容
addWBD(Integer.parseInt(cas.getId()), Constants.ACTURL_WRITER_BACK_CELL_NUM, body);
//6、数据库后置查询结果
Object afterSqlResult = SqlUtils.querySingle(cas.getCheckSQL());
//7、数据库断言
boolean sqlFlag = sqlAssert(cas, beforeSqlResult, afterSqlResult);
System.out.println("数据库断言结果:" + sqlFlag);
//8、添加断言回写内容
String assertContent = (assertResponseFlag && sqlFlag) ? "Pass" : "Fail";
addWBD(Integer.parseInt(cas.getId()), Constants.ASSERT_RESULT_CELL_NUM, assertContent);
//9、添加日志
//10、报表断言
}
/**
* 注册数据库断言方法
*
* @param beforeSqlResult
* @param afterSqlResult
* @return
*/
public boolean sqlAssert(Case cas, Object beforeSqlResult, Object afterSqlResult) {
String sql = cas.getCheckSQL();
//如果sql为空,说明不需要数据库断言
if (StringUtils.isBlank(sql)) {
return true;
} else {
//注册断言逻辑:前置sql结果为0,后置sql结果为1,其他情况断言失败
long beforeValue = (long) beforeSqlResult;
long afterValue = (long) afterSqlResult;
System.out.println("sql:" + sql);
System.out.println("beforeValue:" + beforeValue);
System.out.println("afterValue:" + afterValue);
if (beforeValue == 0 && afterValue == 1) {
return true;
} else {
return false;
}
}
}
@DataProvider(name = "datas0")
public Object[][] datas0() {
//Object[m][n] m代表执行次数,n代表参数个数
Object[][] datas = {
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110011\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110012\",\"pwd\":\"123456\"}"},
{"http://api.lemonban.com/fetureloan/member/register", "{\"mobile_phone\":\"15500110013\",\"pwd\":\"123456\"}"},
};
return datas;
}
@DataProvider(name = "datas1")
public Object[][] datas1() {
Object[][] datas = ExcelUtils.getAPIAndCaseByApiId("1");
return datas;
}
}
package com.lemon.constants;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-24 11:52
**/
public class Constants {
/*
* 用于存放一些常量,Excel的路径等等
* 常量类命名规则:所有英文单词都大写用下划线分割。
* final:修饰变量,变量成为常量,常量只能赋值一次
* final:修饰类,类不能被继承
* final:修饰方法,不能被重写
*/
//excel用例路径
public static final String EXCEL_PATH = "src/test/resources/测试用例.xls";
//token鉴权版本
public static final String HEADER_MEDIA_TYPE_NAME = "X-Lemonban-Media-Type";
//token鉴权方式值
public static final String HEADER_MEDIA_TYPE_VALUE = "lemonban.v2";
public static final String CONTENT_TYPE_NAME = "Content-Type";
public static final String CONTENT_TYPE_VALUE = "application/json";
// Excel回写的列数:实际响应结果
public static final int ACTURL_WRITER_BACK_CELL_NUM = 5;
// Excel回写的列数:判断回写结果列
public static final int ASSERT_RESULT_CELL_NUM = 5;
// 数据库连接信息
public static final String JDBC_URL = "jdbc:mysql://api.lemonban.com:3306/futureloan?useUnicode=true&characterEncoding=utf-8";
//数据库用户名
public static final String JDBC_USERNAME = "future";
//数据库密码
public static final String JDBC_PASSWORD = "123456";
}
package com.lemon.httpclient;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.http.HttpClient;
import java.util.Arrays;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 12:06
**/
public class GetDemo {
/*
* 1、创建request请求
* 2、选择请求方法method
* 3、填写URL
* 4、有参传参、有头加头
* 5、点击发送按钮
* 6、接收响应
* 7、格式化响应内容(body、status、headers)
*/
public static void main(String[] args) throws Exception {
// 1、2、3步骤
HttpGet httpGet = new HttpGet("http://api.lemonban.com/fetureloan/loans");
// 4、有参传参、有头加头
httpGet.addHeader("X-Lemonban-Media-Type", "lemonban.v1");
// 5、点击发送按钮,模拟客户端发送请求
CloseableHttpClient client = HttpClients.createDefault();
//记录开始时间
long startTime = System.currentTimeMillis();
// 由客户端发出请求,6、接收响应
CloseableHttpResponse response = client.execute(httpGet);
//记录结束时间
long endTime = System.currentTimeMillis();
// 获取body
HttpEntity entity = response.getEntity();
// 获取状态码
int statusCode = response.getStatusLine().getStatusCode();
// 获取header
Header[] headers = response.getAllHeaders();
System.out.println(EntityUtils.toString(entity));
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
System.out.println("接口响应时间(毫秒):" + (endTime - startTime));
}
}
package com.lemon.httpclient;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.util.Arrays;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 12:59
**/
public class HostDemo {
/*
* 加代理
*/
public static void main(String[] args) throws Exception {
// 1、2、3
HttpPost httpPost = new HttpPost("http://api.lemonban.com/fetureloan/login");
// 4、有参传参、有头加头
httpPost.setHeader("X-Lemonban-Media-Type", "lemonban.v1");
// Post请求必须添加content-type
httpPost.setHeader("Content-Type", "application/x-www-from-urlencoded;charset=UTF-8");
// 传参
httpPost.setEntity(new StringEntity("username=15500220022&password=123456"));
// 5、点击发送按钮
CloseableHttpClient httpClient = HttpClients.createDefault();
// HttpHost加代理
HttpHost host = new HttpHost("127.0.0.1", 8899);
// 6、接收响应
CloseableHttpResponse response = httpClient.execute(host,httpPost);
// 获取body
HttpEntity entity = response.getEntity();
// 获取状态码
int statusCode = response.getStatusLine().getStatusCode();
// 获取header
Header[] headers = response.getAllHeaders();
System.out.println(EntityUtils.toString(entity));
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
}
}
package com.lemon.httpclient;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 12:43
**/
public class PostDemo {
/*
* 1、创建request请求
* 2、选择请求方法method
* 3、填写URL
* 4、有参传参、有头加头
* 5、点击发送按钮
* 6、接收响应
* 7、格式化响应内容(body、status、headers)
*/
public static void main(String[] args) throws Exception {
// 1、2、3
HttpPost httpPost = new HttpPost("http://api.lemonban.com/fetureloan/login");
// 4、有参传参、有头加头
httpPost.setHeader("X-Lemonban-Media-Type", "lemonban.v1");
// Post请求必须添加content-type
httpPost.setHeader("Content-Type", "application/json");
// 传参
httpPost.setEntity(new StringEntity("{\"mobile_phone\":\"15500110011\",\"pwd\":\"123456\"}"));
// 5、点击发送按钮
CloseableHttpClient httpClient = HttpClients.createDefault();
// 6、接收响应
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取body
HttpEntity entity = response.getEntity();
// 获取状态码
int statusCode = response.getStatusLine().getStatusCode();
// 获取header
Header[] headers = response.getAllHeaders();
System.out.println(EntityUtils.toString(entity));
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
}
}
package com.lemon.httpclient;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.util.Arrays;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 12:54
**/
public class PostDemo2 {
public static void main(String[] args) throws Exception {
// 1、2、3
HttpPost httpPost = new HttpPost("http://api.lemonban.com/fetureloan/login");
// 4、有参传参、有头加头
httpPost.setHeader("X-Lemonban-Media-Type", "lemonban.v1");
// Post请求必须添加content-type
httpPost.setHeader("Content-Type", "application/x-www-from-urlencoded;charset=UTF-8");
// 传参
httpPost.setEntity(new StringEntity("username=15500220022&password=123456"));
// 5、点击发送按钮
CloseableHttpClient httpClient = HttpClients.createDefault();
// 6、接收响应
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取body
HttpEntity entity = response.getEntity();
// 获取状态码
int statusCode = response.getStatusLine().getStatusCode();
// 获取header
Header[] headers = response.getAllHeaders();
System.out.println(EntityUtils.toString(entity));
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
}
}
package com.lemon.json;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-21 17:23
**/
public class Demo {
public static void main(String[] args) {
/*
* 静态方法的特点:不需要创建对象,直接用类名就可以调用
*/
// 1、字符串转对象
String json = "{\"name\":\"张三\",\"age\":\"18\"}";
Student student = JSONObject.parseObject(json, Student.class);
System.out.println(student.getName() + "=" + student.getAge());
Map map1 = JSONObject.parseObject(json, Map.class);
System.out.println("map1:" + map1);
// 2、对象转字符串
Student student1 = new Student("lisi", 20);
String s = JSONObject.toJSONString(student1);
System.out.println(s);
// 3、HashMap
HashMap<String, String> map = new HashMap<>();
map.put("code", "200");
map.put("msg", "success");
System.out.println(JSONObject.toJSONString(map));
// 4、字符串数组转成一个list集合
String json2 = "[{\"age\":20,\"name\":\"李四\"},{\"age\":18,\"name\":\"王五\"}]";
List<Student> list = JSONObject.parseArray(json2, Student.class);
for (Student stu : list) {
System.out.println(stu.getName() + "=" + stu.getAge());
}
}
}
package com.lemon.json;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 14:47
**/
public class Dom4jDemo {
/*
* 1、添加依赖:dom4j
* 2、创建解析器SAXReader对象
* 3、获取document对象
* 4、获取根元素
* 5、获取根元素的子元素
* */
public static void main(String[] args) throws DocumentException {
// 创建saxReader对象
SAXReader reader = new SAXReader();
// 通过read方法读取一个文件,转换成Document对象
Document document = reader.read(new File("src/test1.xml"));
// 获取根元素
Element rootElement = document.getRootElement();
// 获取根元素下所有子元素
List<Element> elements = rootElement.elements();
for (Element element : elements) {
// 根元素下的一级子元素
Object data = element.getData();
System.out.println("标签名称:" + element.getName() + "+标签内容:" + data);
}
}
}
package com.lemon.json;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 10:24
**/
public class POIDemo {
/*
* 读:
* 1、打开Excel
* 2、选择sheet
* 3、读取行
* 4、读取列
* 5、修改内容
* 6、回写Excel
* */
public static void main(String[] args) throws IOException, InvalidFormatException {
FileInputStream fis = new FileInputStream("src/test/resources/测试用例.xls");
// Factory 创建xx类的。workbook等于整个Excel
Workbook workbook = WorkbookFactory.create(fis);
// 获取第一个sheet页
Sheet sheet = workbook.getSheetAt(0);
// 获取最后一行。使用普通for和增强for循环
int lastRowNum = sheet.getLastRowNum();
for (int i = 0; i <= lastRowNum; i++) {
// 获取行
Row row = sheet.getRow(i);
short lastCellNum = row.getLastCellNum();
for (int j = 0; j < lastCellNum; j++) {
// 获取单元格
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
// 将单元格数据转为String类型
cell.setCellType(CellType.STRING);
// 修改单元格
// cell.setCellValue("3000");
// 回写
// FileOutputStream fos = new FileOutputStream("src/test/resources/测试用例2.xls");
// workbook.write(fos);
//获取单元格数据
String value = cell.getStringCellValue();
System.out.print(value + " ");
}
System.out.println();
}
//关流
fis.close();
}
}
package com.lemon.json;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 15:10
**/
/*
* DOM4J类
DOM4J定义了几个Java类。以下是最常见的类:
Document - 表示整个XML文档。文档Document对象是通常被称为DOM树。
Element - 表示一个XML元素。 Element对象有方法来操作其子元素,它的文本,属性和名称空间。
Attribute - 表示元素的属性。属性有方法来获取和设置属性的值。它有父节点和属性类型。
Node - 代表元素,属性或处理指令
常见DOM4J的方法
当使用DOM4J,还有经常用到的几种方法:
SAXReader.read(xmlSource)() - 构建XML源的DOM4J文档。
Document.getRootElement() - 得到的XML的根元素。
Element.node(index) - 获得在元素特定索引XML节点。
Element.attributes() - 获取一个元素的所有属性。
Node.valueOf(@Name) - 得到元件的给定名称的属性的值。
*
* */
public class ParseXmlDemo {
public void readXML() throws Exception {
// 创建saxReader对象
SAXReader reader = new SAXReader();
// 通过read方法读取一个文件 转换成Document对象
Document document = reader.read(new File("src/test1.xml"));
// 获取根节点元素对象
Element node = document.getRootElement();
// 遍历所有的元素节点
listNodes(node);
elementMethod(node);
}
public void createXML() throws Exception {
Document document = DocumentHelper.createDocument();
Element root = document.addElement("cars");
Element supercarElement = root.addElement("supercars").addAttribute("company", "Ferrai");
supercarElement.addElement("carname").addAttribute("type", "FerrariAttr").addText("FerrariText");
supercarElement.addElement("carname").addAttribute("type", "sportsAttr").addText("sportsText");
// 写入到一个新的文件中
writer(document);
}
/**
* 把document对象写入新的文件
*
* @param document
* @throws Exception
*/
public void writer(Document document) throws Exception {
// 紧凑的格式
// OutputFormat format = OutputFormat.createCompactFormat();
// 排版缩进的格式
OutputFormat format = OutputFormat.createPrettyPrint();
// 设置编码
format.setEncoding("UTF-8");
// 创建XMLWriter对象,指定了写出文件及编码格式
// XMLWriter writer = new XMLWriter(new FileWriter(new
// File("src//a.xml")),format);
XMLWriter writer = new XMLWriter(
new OutputStreamWriter(new FileOutputStream(new File("src//test1.xml")), "UTF-8"), format);
// 写入
writer.write(document);
// 立即写入
writer.flush();
// 关闭操作
writer.close();
}
/**
* 遍历当前节点元素下面的所有(元素的)子节点
*
* @param node
*/
public void listNodes(Element node) {
System.out.println("当前节点的名称::" + node.getName());
// 获取当前节点的所有属性节点
List<Attribute> list = node.attributes();
// 遍历属性节点
for (Attribute attr : list) {
System.out.println(attr.getText() + "-----" + attr.getName() + "---" + attr.getValue());
}
if (!(node.getTextTrim().equals(""))) {
System.out.println("文本内容::::" + node.getText());
}
// 当前节点下面子节点迭代器
Iterator<Element> it = node.elementIterator();
// 遍历
while (it.hasNext()) {
// 获取某个子节点对象
Element e = it.next();
// 对子节点进行遍历
listNodes(e);
}
}
/**
* @param node
*/
public void elementMethod(Element node) {
// 获取node节点中,子节点的元素名称为supercars的元素节点。
Element e = node.element("supercars");
// 获取supercars元素节点中,子节点为carname的元素节点(可以看到只能获取第一个carname元素节点)
Element carname = e.element("carname");
System.out.println(e.getName() + "----" + carname.getText());
// 获取supercars这个元素节点 中,所有子节点名称为carname元素的节点 。
List<Element> carnames = e.elements("carname");
for (Element cname : carnames) {
System.out.println(cname.getText());
}
// 获取supercars这个元素节点 所有元素的子节点。
List<Element> elements = e.elements();
for (Element el : elements) {
System.out.println(el.getText());
}
}
}
package com.lemon.json;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 09:15
**/
public class PropertiesDemo {
/*
*
*
* */
public static void main(String[] args) throws IOException {
// ProPerties 是一个弱化版的HashMap,一般只存在String类型key和value
Properties prop = new Properties();
prop.setProperty("name", "lisi");
prop.setProperty("age", "19");
System.out.println(prop);
FileInputStream file = new FileInputStream("src/test/resources/config.properties");
//读取文件内容
prop.load(file);
FileOutputStream filo = new FileOutputStream("src/test/resources/config.properties");
// 读取文件并重写
prop.store(filo, "beizhu");
System.out.println(prop);
// File操作文件或者文件夹、创建、删除、移动
// IO流
try {
method();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method() throws IOException{
}
}
package com.lemon.json;
import java.util.HashMap;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 10:53
**/
public class StringDemo {
public static void main(String[] args) {
/*
* 题目:有字符串String str="0AAA0BbC1ccc1D23ddd444",分别统计每个字符出现的次数
* 结果:最终输出A: B: C: D: 1: 2: 3: 4:
* */
String str = "0AAA0BbC1ccc1D23ddd444";
char[] charArray = str.toCharArray();
HashMap<Character, Integer> map = new HashMap<>();
for (char c : charArray) {
// 判断是否包含指定的键名c,
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
// 不包含key,第一次存map
map.put(c, 1);
}
}
System.out.println(map);
}
}
package com.lemon.json;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-21 17:25
**/
public class Student {
private String name; //创建的必须是私有的
private int age;
public Student() {
// 空参构造
}
public Student(String name, int age) {
//实参构造
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
}
}
package com.lemon.pojo;
import cn.afterturn.easypoi.excel.annotation.Excel;
import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.NotNull;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 19:35
**/
public class API {
/*属性反射必须私有化 private*/
@Excel(name = "接口编号")
@NotNull // 若该字段验证不通过,则过滤整条Excel数据
private String id;
@Excel(name = "接口名称") //@Email 验证该行是否满足email的格式,若不满足则过滤
private String name;
@Excel(name = "请求方式")
private String method;
@Excel(name = "接口地址")
private String url;
@Excel(name = "参数类型")
private String contentType;
public API() {
}
public API(String id, String name, String method, String url, String contentType) {
this.id = id;
this.name = name;
this.method = method;
this.url = url;
this.contentType = contentType;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getMethod() {
return method;
}
public String getUrl() {
return url;
}
public String getContentType() {
return contentType;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setMethod(String method) {
this.method = method;
}
public void setUrl(String url) {
this.url = url;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}
package com.lemon.pojo;
import cn.afterturn.easypoi.excel.annotation.Excel;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 20:10
**/
public class Case {
@Excel(name = "用例编号")
private String id;
@Excel(name = "用例描述")
private String desc;
@Excel(name = "参数")
private String params;
@Excel(name = "接口编号")
private String apiID;
@Excel(name = "期望响应数据")
private String expectValue;
@Excel(name = "校验SQL")
private String checkSQL;
public Case() {
}
public Case(String id, String desc, String params, String apiID, String expectValue, String checkSQL) {
this.id = id;
this.desc = desc;
this.params = params;
this.apiID = apiID;
this.expectValue = expectValue;
this.checkSQL = checkSQL;
}
public String getId() {
return id;
}
public String getDesc() {
return desc;
}
public String getParams() {
return params;
}
public String getApiID() {
return apiID;
}
public String getExpectValue() {
return expectValue;
}
public String getCheckSQL() {
return checkSQL;
}
public void setId(String id) {
this.id = id;
}
public void setDesc(String desc) {
this.desc = desc;
}
public void setParams(String params) {
this.params = params;
}
public void setApiID(String apiID) {
this.apiID = apiID;
}
public void setExpectValue(String expectValue) {
this.expectValue = expectValue;
}
public void setCheckSQL(String checkSQL) {
this.checkSQL = checkSQL;
}
@Override
public String toString() {
return "Case{" +
"id='" + id + '\'' +
", desc='" + desc + '\'' +
", params='" + params + '\'' +
", apiID='" + apiID + '\'' +
", expectValue='" + expectValue + '\'' +
", checkSQL='" + checkSQL + '\'' +
'}';
}
}
package com.lemon.pojo;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-26 17:12
**/
public class JsonPathVaildate {
// jsonpath表达式
private String expression;
// jsonpath表达式期望找到的值
private String value;
public JsonPathVaildate() {
}
public JsonPathVaildate(String expression, String value) {
this.expression = expression;
this.value = value;
}
public String getExpression() {
return expression;
}
public String getValue() {
return value;
}
public void setExpression(String expression) {
this.expression = expression;
}
public void setValue(String value) {
this.value = value;
}
}
package com.lemon.pojo;
/**
* @program: Lemon
* @description: excel回写数据封装对象
* @author: ray
* @create: 2022-09-26 11:04
**/
public class WriteBackData {
//回写sheet页数
// private int sheetNum;
//回写行号
private int rowNum;
//回写列号
private int cellNum;
//回写内容
private String content;
public WriteBackData() {
}
public WriteBackData(int rowNum, int cellNum, String content) {
this.rowNum = rowNum;
this.cellNum = cellNum;
this.content = content;
}
public int getRowNum() {
return rowNum;
}
public int getCellNum() {
return cellNum;
}
public String getContent() {
return content;
}
public void setRowNum(int rowNum) {
this.rowNum = rowNum;
}
public void setCellNum(int cellNum) {
this.cellNum = cellNum;
}
public void setContent(String content) {
this.content = content;
}
}
package com.lemon.reflex;
import com.lemon.pojo.API;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 20:52
**/
public class reflexDemo {
public static void main(String[] args) throws ClassNotFoundException {
/*
*反射:Java在运行时可以动态的获取任意一个类的对象,
* 并且可以调用这个对象的方法和属性。
*/
// 反射前提:获取到字节码对象,类似于.class文件
Class aClass = API.class;
API api = new API();
Class<? extends API> aClass2 = api.getClass();
Class<?> aClass3 = Class.forName("com.lemon.pojo.API");
System.out.println(aClass == aClass2);
System.out.println(aClass == aClass3);
}
}
package com.lemon.testng;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 16:45
**/
public class TestNGDataProvider {
@Test(dataProvider = "datas")
public void testLogin(String username, String password) {
System.out.println(username + ":" + password);
}
@DataProvider(name = "datas")
public Object[][] datas() {
// Object[][] datas = new Object[1][2];
Object[][] datas = {
{"zhangsan", "123"},
{"wangsans", "456"},
{"zhangpin", "789"},
};
return datas;
}
}
package com.lemon.testng;
import org.testng.annotations.Test;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 16:04
**/
public class TestNGDemo1 {
/*
* 使用TestNG不需要写main方法
*/
@Test(enabled = false)
public void test0() {
System.out.println("TestNGDemo1....test0");
}
// 单个依赖用dependsOnMethods
@Test(dependsOnMethods = "a")
public void test1() {
System.out.println("TestNGDemo1....test1");
}
@Test()
public void test2() {
System.out.println("TestNGDemo1....test2");
}
@Test
public void a() {
System.out.println("...a");
}
}
package com.lemon.testng;
import org.testng.annotations.Test;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 16:04
**/
public class TestNGDemo2 {
/*
* 使用TestNG不需要写main方法
*/
@Test
public void test0() {
System.out.println("TestNGDemo2....test0");
}
@Test
public void test1() {
System.out.println("TestNGDemo2....test1");
}
}
package com.lemon.testng;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-22 16:31
**/
public class TestNGParameters {
// 要使用必须在testng.xml中创建
@Test
@Parameters({"type", "version"})
public void test(String a, String b) {
System.out.println(a + b);
}
}
package com.lemon.utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-26 10:30
**/
public class AuthorizationCookieUtils {
public static Map<String, String> cookies = new HashMap<>();
public static final String RESPONSE_HEADER = "Set-Cookie";
public static final String REQUEST_HEADER = "Cookie";
public static final String COOKIE_NAME = "JSESSIONID";
//抓取cookie存到cookie缓存中
public static void getCookieByResponse(HttpResponse response) {
//从响应头里面获取指定的头字段
Header header = response.getFirstHeader(RESPONSE_HEADER);
//如果header不为空
if (header != null) {
//获取头字段的值
String cookie = header.getValue();
//如果头字段的值不为空
if (StringUtils.isNotBlank(cookie)) {
String[] values = cookie.split(",");
for (String value : values) {
//如果包含JSESSIONID那么放进缓存cookie之中
if (value.contains(COOKIE_NAME)) {
// 将得到cookie为JSESSIONID=03DECD00SXDXWSXFS
cookies.put(COOKIE_NAME, value);
}
}
}
}
}
//从cookie缓存中取出cookie添加到请求头中
public static void addCookieInRequest(HttpRequest request) {
//从缓存中将cookie对应的值取出来
String value = cookies.get(COOKIE_NAME);
//如果cookie不为空,添加到请求头中
if(StringUtils.isNotBlank(value)){
request.setHeader(REQUEST_HEADER,value);
}
}
public static void main(String[] args) {
}
}
package com.lemon.utils;
import bsh.StringUtil;
import com.alibaba.fastjson.JSONPath;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @program: Lemon
* @description: 鉴权类
* @author: ray
* @create: 2022-09-24 16:22
**/
public class AuthorizationUtils {
// 定义为静态,随着类加载而加载,模拟的一个环境变量
public static final Map<String, String> env = new HashMap<>();
/**
* 1、从接口响应中获取token信息
* 2、把Token信息存储到环境变量中
* 使用jsonpath: fastjson 1.2.0之后的版本支持JSONPath。这是一个很强大的功能,可以在java框架中当作对象查询语言(OQL)来使用。
* @param response:
*/
public static void storeToken(String response) {
Object token = JSONPath.read(response, "$.data.token_info.token");
// 如果Token不为空说明登录成功
if (token != null) {
//将Token存储到环境变量
env.put("token", token.toString());
// 如果Token不为空,那么获取用户ID并且存储
Object memberId = JSONPath.read(response, "$data.id");
if (memberId != null) {
env.put("${member_id}", memberId.toString());
}
}
}
/**
* 判断环境变量中是否存在Token值,如果存在的话,在发送请求时设置token
*
* @param request
*/
public static void setTokenInRequest(HttpRequest request) {
// 从环境变量中取出Token
String token = env.get("token");
// 判断如果token不为空
if (StringUtils.isNotBlank(token)) {
// 将token设置到header中
request.setHeader("Authorization", "Bearer " + token);
}
}
public static void main(String[] args) {
String json = "{\"errno\":0,\"errmsg\":\"ok\",\"IsPrint\":false,\"data\":{\"log_id\":\"1354006722083980421\",\"action_rule\":{\"pos_1\":[],\"pos_2\":[],\"pos_3\":[]}}}";
// 精准搜索:按层级匹配
Object read = JSONPath.read(json, "$.data.log_id");
//模糊搜索:默认为数组,找到的是所有的多个匹配值
Object read1 = JSONPath.read(json, "$..log_id");
System.out.println(read);
}
}
package com.lemon.utils;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.lemon.constants.Constants;
import com.lemon.pojo.API;
import com.lemon.pojo.Case;
import com.lemon.pojo.WriteBackData;
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 14:23
**/
public class ExcelUtils {
//读取Excel中第1个sheet,API数据
public static List<API> apiList = read(0, API.class);
//读取Excel中第2个sheet,Case数据
public static List<Case> caseList = read(1, Case.class);
//回写Excel数据集合
public static List<WriteBackData> wbdList = new ArrayList<>();
public static <E> List<E> read(int startSheetIndex, Class<E> clazz) {
// 定义泛型 决定E的类型
FileInputStream fis = null;
try {
// 1、创建流,加载Excel文件
fis = new FileInputStream(Constants.EXCEL_PATH);
// 2、导入配置,创建空对象相当于用默认配置
ImportParams params = new ImportParams();
// 3、设置sheet页
params.setStartSheetIndex(startSheetIndex);
// 4、是否需要进行excel验证,判断某个字段是否为空,若为空则过滤
params.setNeedVerify(true);
// 4、执行导入excel文件
List<E> list = ExcelImportUtil.importExcel(fis, clazz, params);
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
close(fis);
}
return null;
}
/**
* 流关闭方法
*
* @param stream
*/
private static void close(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 批量回写
*/
// 不用传参,因为集合为静态方法,修改Excel需要用到原生的poi
public static void batchWrite() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(Constants.EXCEL_PATH);
Workbook workbook = WorkbookFactory.create(fis);
Sheet sheet = workbook.getSheetAt(1);
//回写操作行和列
//1、遍历wbdList集合
for (WriteBackData wbd : wbdList) {
//2、获取行号,根据行号获取row对象
int rowNum = wbd.getRowNum();
Row row = sheet.getRow(rowNum);
//3、获取列号,根据列号获取cell对象
int cellNum = wbd.getCellNum();
Cell cell = row.getCell(cellNum, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
//4、获取回写内容,设置到cell中
cell.setCellType(CellType.STRING);
String content = wbd.getContent();
// 5、将数据设置到Excel对应行和列中
cell.setCellValue(content);
}
fos = new FileOutputStream(Constants.EXCEL_PATH);
workbook.write(fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
close(fis);
close(fos);
}
}
/*
* 从已经读取很多所有list<API>和所有list<Case>
* 两个集合中获取符合条件的数据
*/
public static Object[][] getAPIAndCaseByApiId(String apiId) {
// 需要API对象
API wantAPI = null;
// 需要Case集合
ArrayList<Case> wantCaseList = new ArrayList<>();
// 匹配API对象
for (API api : apiList) {
//如果apiId和api集合中的apiId相等则返回
if (apiId.equals(api.getId())) {
wantAPI = api;
break;
}
}
// 匹配Case对象
for (Case aCase : caseList) {
//如果apiId和case集合中的apiId相等则返回
if (apiId.equals(aCase.getApiID())) {
wantCaseList.add(aCase);
}
}
// wantCaselist和wantAPI是有关联的,他们的apiId相等。一个API接口对应多条Case
Object[][] datas = new Object[wantCaseList.size()][2];
// 往二维数组中存储API和Case数据,存几次由Case决定
for (int i = 0; i < wantCaseList.size(); i++) {
datas[i][0] = wantAPI;
datas[i][1] = wantCaseList.get(i);
}
return datas;
}
public static Object[][] readTwo() {
FileInputStream fis = null;
Object[][] datas = null;
try {
fis = new FileInputStream(Constants.EXCEL_PATH);
Workbook workbook = WorkbookFactory.create(fis);
Sheet sheet = workbook.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum();
//跳过表头第一行,从1开始取值
datas = new Object[lastRowNum][4]; // 后面有几个参数写死
for (int i = 1; i <= lastRowNum; i++) {
Row row = sheet.getRow(i);
// 获取URL
Cell urlCell = row.getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
urlCell.setCellType(CellType.STRING);
String urlValue = urlCell.getStringCellValue();
datas[i - 1][0] = urlValue;
// 获取type
Cell typeCell = row.getCell(3, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
typeCell.setCellType(CellType.STRING);
String typeValue = typeCell.getStringCellValue();
datas[i - 1][1] = typeValue;
// 获取 params
Cell paramsCell = row.getCell(3, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
paramsCell.setCellType(CellType.STRING);
String paramsValue = paramsCell.getStringCellValue();
datas[i - 1][2] = paramsValue;
// 获取 content-type
Cell contentTypeCell = row.getCell(4, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
contentTypeCell.setCellType(CellType.STRING);
String contentTypeValue = contentTypeCell.getStringCellValue();
datas[i - 1][3] = contentTypeValue;
// System.out.println("url:" + urlValue + ",type:" + typeValue + ",params:" + paramsValue + ",content-type:" + contentTypeValue);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return datas;
}
public static void main(String[] args) throws Exception {
List<API> apiList = read(0, API.class);
List<Case> caseList = read(1, Case.class);
System.out.println(apiList);
}
}
package com.lemon.utils;
import com.alibaba.fastjson.JSONObject;
import com.lemon.constants.Constants;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-23 13:11
**/
public class HttpUtils {
/*
* static 修饰方法和变量
* 静态特点:
* 0、直接用类名点击调用
* 1、被所有的对象共享(环境变量)
* 2、所有类加载而加载
*/
/**
* call :方法 发起请求
*
* @param url:URL
* @param type:Post请求、get请求
* @param params:请求参数
* @param contentType:请求类型,JSON或from
*/
public static String call(String url, String type, String params, String contentType, boolean isAuthorization) {
try {
// 如果说JSON类型请求方式
if ("json".equalsIgnoreCase(contentType)) {
//如果是Post请求
if ("post".equalsIgnoreCase(type)) {
return HttpUtils.jsonPost(url, params, isAuthorization);
} else if ("get".equalsIgnoreCase(type)) {
//如果是get请求
return HttpUtils.jsonGet(url);
} else if ("patch".equalsIgnoreCase(type)) {
//如果是patch请求
return HttpUtils.jsonPatch(url, params, isAuthorization);
}
} else if ("from".equalsIgnoreCase(contentType)) {
if ("post".equalsIgnoreCase(type)) {
// JSON类型参数转换为from类型参数
params = HttpUtils.json2from(params);
return HttpUtils.fromPost(url, params, isAuthorization);
} else if ("get".equalsIgnoreCase(type)) {
return HttpUtils.fromGet(url, params);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String json2from(String json) {
// 1、JSON转换成map
HashMap<String, String> map = JSONObject.parseObject(json, HashMap.class);
// 2、获取所有的key
Set<String> keySet = map.keySet();
// 3、定义返回结果字符串
String result = "";
// 4、循环遍历所有key和value
for (String key : keySet) {
// 5、通过键key找值value
String value = map.get(key);
if (result.length() > 0) {
result += "&";
}
//拼接
result += key + "=" + value;
}
return result;
}
public static String fromGet(String url, String params) throws Exception {
// login?username=15500110011&password=123456
HttpGet httpGet = new HttpGet(url + "?" + params);
httpGet.addHeader(Constants.HEADER_MEDIA_TYPE_NAME, Constants.HEADER_MEDIA_TYPE_VALUE);
CloseableHttpClient client = HttpClients.createDefault();
long startTime = System.currentTimeMillis();
CloseableHttpResponse response = client.execute(httpGet);
long endTime = System.currentTimeMillis();
HttpEntity entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getAllHeaders();
String body = EntityUtils.toString(entity);
System.out.println(body);
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
System.out.println("接口响应时间(毫秒):" + (endTime - startTime));
return body;
}
public static String jsonGet(String url) throws Exception {
// login?username=15500110011&password=123456
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader(Constants.HEADER_MEDIA_TYPE_NAME, Constants.HEADER_MEDIA_TYPE_VALUE);
CloseableHttpClient client = HttpClients.createDefault();
long startTime = System.currentTimeMillis();
CloseableHttpResponse response = client.execute(httpGet);
long endTime = System.currentTimeMillis();
HttpEntity entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getAllHeaders();
String body = EntityUtils.toString(entity);
System.out.println(body);
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
System.out.println("接口响应时间(毫秒):" + (endTime - startTime));
return body;
}
public static String jsonPost(String url, String params, Boolean isAuthorization) throws Exception {
HttpPost httpPost = new HttpPost(url);
// 有参传参、有头加头
httpPost.setHeader(Constants.HEADER_MEDIA_TYPE_NAME, Constants.HEADER_MEDIA_TYPE_VALUE);
// Post请求必须添加content-type
httpPost.setHeader("Content-Type", "application/json");
// 添加鉴权头
if (isAuthorization) {
AuthorizationUtils.setTokenInRequest(httpPost);
}
// 传参
httpPost.setEntity(new StringEntity(params, "UTF-8"));
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getAllHeaders();
String body = EntityUtils.toString(entity);
System.out.println(body);
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
return body;
}
public static String fromPost(String url, String params, Boolean isAuthorization) throws Exception {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader(Constants.HEADER_MEDIA_TYPE_NAME, Constants.HEADER_MEDIA_TYPE_VALUE);
httpPost.setHeader("Content-Type", "application/x-www-from-urlencoded;charset=UTF-8");
// 添加鉴权头
if (isAuthorization) {
AuthorizationUtils.setTokenInRequest(httpPost);
}
httpPost.setEntity(new StringEntity(params, "UTF-8"));
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getAllHeaders();
String body = EntityUtils.toString(entity);
System.out.println(body);
System.out.println(statusCode);
System.out.println(Arrays.toString(headers));
return body;
}
public static String jsonPatch(String url, String params, Boolean isAuthorization) throws Exception {
HttpPatch patch = new HttpPatch(url);
patch.setHeader(Constants.HEADER_MEDIA_TYPE_NAME, Constants.HEADER_MEDIA_TYPE_VALUE);
patch.setHeader("Content-Type", "application/json");
// 添加鉴权头
if (isAuthorization) {
AuthorizationUtils.setTokenInRequest(patch);
}
patch.setEntity(new StringEntity(params, "UTF-8"));
CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse response = client.execute(patch);
String body = EntityUtils.toString(response.getEntity());
System.out.println(body);
System.out.println(response.getStatusLine().getStatusCode());
System.out.println(Arrays.toString(response.getAllHeaders()));
return body;
}
public static void main(String[] args) {
}
}
package com.lemon.utils;
import com.lemon.constants.Constants;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-27 10:15
**/
public class JDBCUtils {
/*
* BeanHandler<Object>() 将查询结果的第一行封装成指定的数据类型
* BeanListHandler<Object>() 将查询结果的每一行封装成指定类型的List集合
* ScalarHandler<Long>() 用来获得聚合函数的值,返回类型是Object,用Number来接收比较好
* */
public static void main(String[] args) throws SQLException {
//创建queryRunner对象
QueryRunner runner = new QueryRunner();
//调用查询方法,传入数据库连接、SQL语句、返回值类型
Connection conn = JDBCUtils.getConnection();
//
String sql = "select count(*) from member where mobile_phone='13111111111'";
// 查询操作,使用query
Long result = runner.query(conn, sql, new ScalarHandler<Long>());
System.out.println(result);
}
/*
* 获取数据库连接
* */
public static Connection getConnection() {
//定义数据库连接对象
Connection conn = null;
try {
/*
* 你导入的数据库驱动包:mysql
* jdbc:mysql://api.lemonban.com:3306/fetureloan?useUnicode=true&characterEncoding=utf-8
* jdbc:数据库名称://数据库IP:端口/数据库名称?参数
* */
conn = DriverManager.getConnection(Constants.JDBC_URL, Constants.JDBC_USERNAME, Constants.JDBC_PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭数据库连接
*
* @param conn:传参为数据库连接对象
*/
public static void close(Connection conn) {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.lemon.utils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.apache.commons.lang3.StringUtils;
import java.sql.Connection;
/**
* @program: Lemon
* @description:
* @author: ray
* @create: 2022-09-27 14:20
**/
public class SqlUtils {
/**
* 传入sql语句执行sql查询,并且返回查询结果
*
* @param sql
* @return
*/
public static Object querySingle(String sql) {
Object result = null;
Connection conn = null;
//如果sql语句为空直接返回为空
if (StringUtils.isBlank(sql)) {
return null;
}
try {
//创建queryRunner对象
QueryRunner runner = new QueryRunner();
//调用查询方法,传入数据库连接、SQL语句、返回值类型
conn = JDBCUtils.getConnection();
// 查询操作,使用query
result = runner.query(conn, sql, new ScalarHandler<>());
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn);
}
return result;
}
}
<?xml version="1.0" encoding="utf-8" ?>
<student>
<name>小明</name>
<age>
<a>18</a>
</age>
<score>100</score>
<sex color="red"/>
</student>
\ No newline at end of file
{
"": "",
"": ""
}
\ No newline at end of file
#beizhu
#Thu Sep 22 09:45:13 CST 2022
age=22
name=zhangsan
### set log levels ###
log4j.rootLogger=INFO, console, file, error
### console ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%p]-[%c] %d{yyyy-MM-dd HH\:mm\:ss} method: %l----%m%n
### log file ###
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=../logs/lemon_auto.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=INFO
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
### exception ###
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File=../logs/lemon_auto_error.log
log4j.appender.error.Append=true
log4j.appender.error.Threshold=ERROR
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
# ????????? ${member_id}
${toBeRegisterMobilePhone}=13300110011
${toBeRegisterPassword}=123456789
${toBeLoginMobilePhone}=13400110011
${toBeLoginPassword}=123456789
com/lemon/json/POIDemo.class
com/lemon/pojo/JsonPathVaildate.class
com/lemon/cases/RechargeCase.class
com/lemon/cases/LoginCase.class
com/lemon/json/PropertiesDemo.class
com/lemon/testng/TestNGParameters.class
com/lemon/utils/HttpUtils.class
com/lemon/json/StringDemo.class
com/lemon/pojo/API.class
com/lemon/testng/TestNGDemo1.class
com/lemon/utils/AuthorizationCookieUtils.class
com/lemon/pojo/WriteBackData.class
com/lemon/reflex/reflexDemo.class
com/lemon/json/Dom4jDemo.class
com/lemon/json/Demo.class
com/lemon/cases/RegisterCase.class
com/lemon/testng/TestNGDataProvider.class
com/lemon/cases/BaseCase.class
com/lemon/json/Student.class
com/lemon/httpclient/PostDemo.class
com/lemon/utils/ExcelUtils.class
com/lemon/httpclient/PostDemo2.class
com/lemon/utils/AuthorizationUtils.class
com/lemon/httpclient/HostDemo.class
com/lemon/utils/JDBCUtils.class
com/lemon/json/ParseXmlDemo.class
com/lemon/pojo/Case.class
com/lemon/utils/SqlUtils.class
com/lemon/httpclient/GetDemo.class
com/lemon/testng/TestNGDemo2.class
com/lemon/constants/Constants.class
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/cases/LoginCase.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/AuthorizationCookieUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/pojo/Case.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/testng/TestNGDemo1.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/httpclient/PostDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/AuthorizationUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/testng/TestNGDemo2.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/Demo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/constants/Constants.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/httpclient/PostDemo2.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/PropertiesDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/testng/TestNGDataProvider.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/ParseXmlDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/cases/BaseCase.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/Dom4jDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/pojo/API.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/HttpUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/pojo/JsonPathVaildate.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/pojo/WriteBackData.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/cases/RechargeCase.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/Student.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/StringDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/reflex/reflexDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/testng/TestNGParameters.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/JDBCUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/SqlUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/cases/RegisterCase.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/utils/ExcelUtils.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/httpclient/HostDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/json/POIDemo.java
/Users/ray/IdeaProjects/Lemon/src/test/java/com/lemon/httpclient/GetDemo.java
# Created at 2022-09-28T17:51:36.906
java.lang.VerifyError: Expecting a stackmap frame at branch target 100
Exception Details:
Location:
com/lemon/cases/BaseCase.replace(Ljava/lang/String;)Ljava/lang/String; @15: invokestatic
Reason:
Expected stackmap frame at this location.
Bytecode:
0000000: 2b3a 06b2 0155 2a2a 1906 b801 583a 05b8
0000010: 013a 1905 b601 3e2b b800 8c99 0009 2b3a
0000020: 08a7 0050 b200 92b9 0098 0100 b900 9e01
0000030: 004d 2cb9 0057 0100 9900 262c b900 5d01
0000040: 00c0 0073 4eb2 0092 2db9 00a1 0200 c000
0000050: 733a 042b 2d19 04b6 00a5 4ca7 ffd7 2b3a
0000060: 08a7 0010 3a07 b801 3a19 07b6 0142 1907
0000070: bfb8 013a b601 4519 08b0
Exception Handler Table:
bci [15, 100] => handler: 100
at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3434)
at java.base/java.lang.Class.privateGetPublicMethods(Class.java:3459)
at java.base/java.lang.Class.getMethods(Class.java:2051)
at org.testng.internal.TestNGClassFinder.createObjectFactory(TestNGClassFinder.java:254)
at org.testng.internal.TestNGClassFinder.<init>(TestNGClassFinder.java:115)
at org.testng.TestRunner.initMethods(TestRunner.java:370)
at org.testng.TestRunner.init(TestRunner.java:271)
at org.testng.TestRunner.init(TestRunner.java:241)
at org.testng.TestRunner.<init>(TestRunner.java:167)
at org.testng.SuiteRunner$DefaultTestRunnerFactory.newTestRunner(SuiteRunner.java:663)
at org.testng.SuiteRunner.init(SuiteRunner.java:260)
at org.testng.SuiteRunner.<init>(SuiteRunner.java:198)
at org.testng.TestNG.createSuiteRunner(TestNG.java:1295)
at org.testng.TestNG.createSuiteRunners(TestNG.java:1273)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1128)
at org.testng.TestNG.runSuites(TestNG.java:1049)
at org.testng.TestNG.run(TestNG.java:1017)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:283)
at org.apache.maven.surefire.testng.TestNGXmlTestSuite.execute(TestNGXmlTestSuite.java:75)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:120)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
<?xml version="1.0" encoding="utf-8" ?>
<student>
<name>小明</name>
<age>
<a>18</a>
</age>
<score>100</score>
<sex color="red"/>
</student>
\ No newline at end of file
#beizhu
#Thu Sep 22 09:45:13 CST 2022
age=22
name=zhangsan
### set log levels ###
log4j.rootLogger=INFO, console, file, error
### console ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%p]-[%c] %d{yyyy-MM-dd HH\:mm\:ss} method: %l----%m%n
### log file ###
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=../logs/lemon_auto.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=INFO
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
### exception ###
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File=../logs/lemon_auto_error.log
log4j.appender.error.Append=true
log4j.appender.error.Threshold=ERROR
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
# ????????? ${member_id}
${toBeRegisterMobilePhone}=13300110011
${toBeRegisterPassword}=123456789
${toBeLoginMobilePhone}=13400110011
${toBeLoginPassword}=123456789
<?xml version="1.0" encoding="utf-8" ?>
<suite name="柠檬前程贷" parallel="false"> <!-- suite 套件/项目-->
<test name="登录模块"> <!-- 模块-->
<classes>
<class name="com.lemon.cases.LoginCase"/> <!-- 测试类/用例类-->
</classes>
</test>
<test name="注册模块"> <!-- 模块-->
<classes>
<class name="com.lemon.cases.RegisterCase"/> <!-- 测试类/用例类-->
</classes>
</test>
<!-- <test name="模块"> &lt;!&ndash; 模块&ndash;&gt;-->
<!-- <classes>-->
<!-- <class name="com.lemon.testng.TestNGParameters"/> &lt;!&ndash; 测试类/用例类&ndash;&gt;-->
<!-- </classes>-->
<!-- </test>-->
<parameter name="type" value="phone"/>
<parameter name="version" value="1.1.1"/>
</suite>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment