Windows batch file – Short tutorial + Run tests from multiple modules

Let’s start with some batch basics. If you are already familiar with them skip this section.

  • @echo off – Should be added at the top of your batch script to prevent printing all commands.
  • echo Some text Output: “Some text”
  • echo. – Empty line
  • set /a index=0 – Set numeric variable
  • echo Index is %index% – Output: “Index is 0”
  • Rem It is a comment
  • :: It is a comment too
  • echo Some text>> test.txt – Write “Some text” to test.txt file.

Functions

To declare a function we use ” : ” and the name of a function. And to mark the end of a function we add: EXIT /B 0

:PrintMyName
    echo Alexey Korolev
EXIT /B 0

As you guessed this function will print my name. You will ask how we can call functions: CALL : PrintMyName

Functions with arguments

The parameters in the function are marked as %~1, %~2, %~3

If we want to call the function bellow: CALL : PrintHeader “Param1”

:PrintHeader
    echo ==================================================
    echo       %~1
    echo ==================================================
EXIT /B 0

Separating functions from the main code

@echo off
echo Main code it here
CALL : PrintHeader "Param1"

:: This line should be added before your funcitons
EXIT /B %ERRORLEVEL%

:PrintHeader
    echo ==== %~1 ====
EXIT /B 0

For Loops

There is a lot of them, but we will cover only the ones we need.

Get the output of some command line by line

for /f %%i in ('adb shell pm list packages') do (
	echo %%i
)

The code below will print all the packages are existing on your device. And the following code will show us how we check if some package existent/installed on a device:

for /f %%i in ('adb shell pm list packages ^| findstr com.example.app') do (
	set isExist=%%i
)

if defined isExist (echo Installed) else (echo Not installed)

List iteration with for

set "someList=FirestElement SecondElement ThirdElement"
for %%x in (%someList%) do (
       echo %%x
)

For loop with index

  • Delayed Expansion will cause variables within a batch file to be expanded at execution time rather than at parse time, this option is turned on with the SETLOCAL EnableDelayedExpansion command.
  • When the delayed expansion is in effect, variables can be immediately read using !variable_name! you can still read and use %variable_name% but that will continue to show the initial value
SETLOCAL EnableDelayedExpansion

set /a index=0

for %%x in (%someList%) do (
       echo !index! - %%x
       set /a index=!index! + 1
)

ENDLOCAL

Run tests from multiple modules

First, we will declare variables with project location, APKs locations and more.

@echo off

:: Project folder
set DIR=%USERPROFILE%/AndroidStudioProjects/project_folder

:: Locations of APK files used for tests
set APK1=%DIR%/module_name/build/outputs/apk/androidTest/debug/module_name-debug-androidTest.apk
set APK2=%DIR%/module_name_2/build/outputs/apk/androidTest/debug/module_name_2-debug-androidTest.apk

:: Location on device where we will push APKs before installing
set TMP1=/data/local/tmp/app.example.com.module_name
set TMP2=/data/local/tmp/app.example.com.module_name_2

:: Test package name
set PCKG1=app.example.com.module_name.test
set PCKG2=app.example.com.module_name_2.test

:: Packages prefixes, used when we call for tests
set PREFIX=com.example.app.
set PREFIX2=com.example.app2.

:: Path for JUnit Runners
set androidJUnitRunnerPath1=app.example.com.module_name.test/android.support.test.runner.AndroidJUnitRunner
set androidJUnitRunnerPath2=app.example.com.module_name2.test/androidx.test.runner.AndroidJUnitRunner

Git pull

echo Pull project from GIT...
git pull

Header printing function

:: ============== FUNCTIONS ===================
EXIT /B %ERRORLEVEL%

:PrintHeader
    echo. & echo ==================================================
    echo       %~1
    echo ================================================== & echo.
EXIT /B 0

Gradle task function

:GradleTasks
    CALL :PrintHeader "Gradle tasks - clean task"
    cd..
    call gradlew clean
    cls & CALL :PrintHeader "Gradle tasks - assembleDebug task"
    call gradlew assembleDebug
    cls & CALL :PrintHeader "Gradle tasks - assembleDebugAndroidTest task"
    call gradlew assembleDebugAndroidTest
    cd scripts
    cls
EXIT /B 0

Set a list with tests names

echo Pull project from GIT...
git pull

:: gradlew clean + assembleDebug + assembleDebugAndroidTest
CALL :GradleTasks

SETLOCAL EnableDelayedExpansion
set "testArr=FirstTest SecondTest ThirdTest"

ENDLOCAL

A function that prepares APK for test

As a first argument, we need to pass a package name of the test module. As a second argument, we pass APK location and finally as a third argument we pass a location where APK would be saved on the device. The fourth argument is just a title for the log. The fifth is a variable that allows us to know if the function succeeded.

:PrepareApkForTests

CALL :PrintHeader "Running %~4 tests"

    echo Check if APK exist in project folder...
    if exist %~2 (echo APK exist) else (
        echo APK not exist. Break.
        EXIT /B 0
    )
    echo. & echo Uploading the apk into the device...
    adb push %~2 %~3
    echo. & echo Uninstalling current project if exist...
    adb shell pm uninstall %~1
    echo. & echo Installing the apk...
    adb shell pm install -t -r %~3

    set %~5=1
EXIT /B 0

A method running the tests

Ad a first argument we pass a PREFIX, as a second argument we pass android JUnit Runner Path. And the third argument is a list of tests.

:RunTests
    echo. & echo Run all tests on the device... & echo.

    :: Back button click - Exit from screen saver
    adb shell input keyevent 4

    set /a i=0
    for %%x in (%*) do (
    	if !i! gtr 1 (
    		echo Execute: %~1%%x...

    		set /a index=0

    		for /f "tokens=*" %%k in ('adb shell am instrument -w -r -e debug false -e class %~1%%x %~2') do (
    			::echo !index! - %%k
    			set result[!index!]=%%k
    			set /a index=!index! + 1
    			(echo %%k | findstr /i /c:"OK" >nul) && (set isTestPassed=true)
    		)

    		if defined isTestPassed (echo Test OK) else (
    			echo Test failed
    			set /a index=!index! - 1
    			for /L %%f in (0,1,!index!) do (
    				::echo !result[%%f]!
    				echo !result[%%f]!>> logs.txt
    			)
    		)
    	)
    	set /a i=!i! + 1
    )
EXIT /B 0

Final code

@echo off

:: ============== VARIABLES===================
:: Variables are here

:: ============== MAIN CODE===================

echo Pull project from GIT...
git pull

:: gradlew clean + assembleDebug + assembleDebugAndroidTest
CALL :GradleTasks

SETLOCAL EnableDelayedExpansion
    set "testArr=FirstTest SecondTest ThirdTest"
    CALL :PrepareApkForTests %PCKG1% %APK1% %TMP1% "Test 1" ok
    if defined ok (CALL :RunTests %PREFIX% %androidJUnitRunnerPath1% %testArr%)
ENDLOCAL

SETLOCAL EnableDelayedExpansion
    set "testArr=FirstTest SecondTest ThirdTest"
    CALL :PrepareApkForTests %PCKG2% %APK2% %TMP2% "Test 2" ok
    if defined ok (CALL :RunTests %PREFIX2% %androidJUnitRunnerPath2% %testArr%)
ENDLOCAL

:: ============== FUNCTIONS ===================

EXIT /B %ERRORLEVEL%

:PrintHeader
    echo. & echo ==================================================
    echo       %~1
    echo ================================================== & echo.
EXIT /B 0


:PrepareApkForTests

CALL :PrintHeader "Running %~4 tests"

    echo Check if APK exist in project folder...
    if exist %~2 (echo APK exist) else (
        echo APK not exist. Break.
        EXIT /B 0
    )
    echo. & echo Uploading the apk into the device...
    adb push %~2 %~3
    echo. & echo Uninstalling current project if exist...
    adb shell pm uninstall %~1
    echo. & echo Installing the apk...
    adb shell pm install -t -r %~3

    set %~5=1
EXIT /B 0


:RunTests
    echo. & echo Run all tests on the device... & echo.

    :: Back button click - Exit from screen saver
    adb shell input keyevent 4

    set /a i=0
    for %%x in (%*) do (
    	if !i! gtr 1 (
    		echo Execute: %~1%%x...

    		set /a index=0

    		for /f "tokens=*" %%k in ('adb shell am instrument -w -r -e debug false -e class %~1%%x %~2') do (
    			::echo !index! - %%k
    			set result[!index!]=%%k
    			set /a index=!index! + 1
    			(echo %%k | findstr /i /c:"OK" >nul) && (set isTestPassed=true)
    		)

    		if defined isTestPassed (echo Test OK) else (
    			echo Test failed
    			set /a index=!index! - 1
    			for /L %%f in (0,1,!index!) do (
    				::echo !result[%%f]!
    				echo !result[%%f]!>> logs.txt
    			)
    		)
    	)
    	set /a i=!i! + 1
    )
EXIT /B 0

*** & amp ; => &


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.