Automating console (CLI) applications (Windows)

Last edited on

Overview

Even though Squish focuses on automating GUI applications it is possible to do some limited testing of console applications by using cmd.exe and some small workarounds.

Python Example

Let's imagine that we have the following simple batch file mycommand.bat:

@echo off

echo What is your name?
echo.
set _input=
set /p _input=?

echo.
echo Hello %_input%.
echo.

echo How old are you, %_input%?
echo.
set _input=
set /p _input=?

echo.
echo Really?! Sorry, I had no idea!
echo.

echo Do you want to proceed?
echo.
set _input=
set /p _input=?
mycommand.bat

To test this we can write a Squish test script which automates the following via the type() command and other functionality in Squish:

Here is such a test script written in Python:

# -*- coding: utf-8 -*-"

import os
import os.path

from toplevelwindow import *


def main():
    # The 'program' variable holds the name of the AUT
    # including its full path by making use of the
    # squishinfo.testCase property which holds the test
    # case's folder name. It assumes that the AUT is
    # in the test suite folder (i.e., the folder above
    # the test case).
    # Make sure to enclose paths and arguments in double quotes,
    # unless you are 100% sure that this is not needed:
    program = '"' + squishinfo.testCase + "\\..\\mycommand.bat" + '"'


    # Start cmd.exe:
    start_cmd_exe()


    # Ensure a simple prompt:
    type_into_cmd_window("prompt $G ")
    type_into_cmd_window("<Return>")


    # Clear screen:
    type_into_cmd_window("cls")
    type_into_cmd_window("<Return>")


    # Start our program/batch file:
    type_into_cmd_window(program)
    type_into_cmd_window("<Return>")

    # Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n?"
    actual = get_text_from_cmd_window()
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>")
    test.compare(expected, actual)


    # Enter name "John":
    type_into_cmd_window("John")
    type_into_cmd_window("<Return>")

    # Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n? John\r\n\r\nHello John.\r\n\r\nHow old are you, John?\r\n\r\n?"
    actual = get_text_from_cmd_window()
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>")
    test.compare(expected, actual)


    # Enter age "21":
    type_into_cmd_window("21")
    type_into_cmd_window("<Return>")

    # Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n? John\r\n\r\nHello John.\r\n\r\nHow old are you, John?\r\n\r\n? 21\r\n\r\nReally?! Sorry, I had no idea!\r\n\r\nDo you want to proceed?\r\n\r\n?"
    actual = get_text_from_cmd_window()
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>")
    test.compare(expected, actual)


def get_text_from_cmd_window(objOrName_cmd_window={"type": "Window"}):
    # Mark all:
    type_into_cmd_window("<Ctrl+a>", objOrName_cmd_window, 0)

    # Copy marked text to clipboard:
    type_into_cmd_window("<Return>", objOrName_cmd_window, 0)

    # Copying to clipboard may take a short moment:
    snooze(0.1)

    # Use getClipboardText() to get the text data
    # in the clipboard; also see:
    # https://doc.qt.io/squish/squish-api.html#getclipboardtext-function
    return getClipboardText()


def cmd_to_foreground(objOrName_cmd_window={"type": "Window"}):
    win = ToplevelWindow.byName(objOrName_cmd_window);
    win.setForeground();
    win.setFocus();


def type_into_cmd_window(text, objOrName_cmd_window={"type": "Window"}, delay=1.0):
    cmd_to_foreground(objOrName_cmd_window)
    type(objOrName_cmd_window, text)
    snooze(delay)


def start_cmd_exe():
    aut = os.path.join(os.environ["WINDIR"], "system32", "cmd")
    testSettings.setWrappersForApplication(aut, ["Windows"])
    return startApplication('"%s" /c start /wait cmd.exe' % aut)
test.py

JavaScript Example

source(findFile("scripts", "javascript/toplevelwindow.js"));


function main()
{
    // The 'program' variable holds the name of the AUT
    //including its full path by making use of the
    // squishinfo.testCase property which holds the test
    // case's folder name. It assumes that the AUT is
    // in the test suite folder (i.e., the folder above
    // the test case).
    program = squishinfo.testCase + "\\..\\mycommand.bat";


    // Start cmd.exe:
    start_cmd_exe();


    // Ensure a simple prompt:
    type_into_cmd_window("prompt $G ");
    type_into_cmd_window("<Return>");


    // Clear screen:
    type_into_cmd_window("cls");
    type_into_cmd_window("<Return>");


    // Start output program/batch file:
    type_into_cmd_window(program);
    type_into_cmd_window("<Return>");

    // Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n?";
    actual = get_text_from_cmd_window();
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>");
    test.compare(expected, actual);


    // Enter name "John":
    type_into_cmd_window("John");
    type_into_cmd_window("<Return>");

    // Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n? John\r\n\r\nHello John.\r\n\r\nHow old are you, John?\r\n\r\n?";
    actual = get_text_from_cmd_window();
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>");
    test.compare(expected, actual);


    // Enter age "21":
    type_into_cmd_window("21");
    type_into_cmd_window("<Return>");

    // Verify expected output:
    expected = "\r\n> <PROGRAM>\r\nWhat is your name?\r\n\r\n? John\r\n\r\nHello John.\r\n\r\nHow old are you, John?\r\n\r\n? 21\r\n\r\nReally?! Sorry, I had no idea!\r\n\r\nDo you want to proceed?\r\n\r\n?";
    actual = get_text_from_cmd_window();
    actual = actual.replace("\r\n> " + program, "\r\n> <PROGRAM>");
    test.compare(expected, actual);
}


function get_text_from_cmd_window(objOrName_cmd_window_optional)
{
    if (objOrName_cmd_window_optional == null) {
        objOrName_cmd_window_optional = {"type": "Window"};
    }

    // Mark all:
    type_into_cmd_window("<Ctrl+a>", objOrName_cmd_window_optional, 0);

    // Copy marked text to clipboard:
    type_into_cmd_window("<Return>", objOrName_cmd_window_optional, 0);

    // Copying to clipboard may take a short moment:
    snooze(0.1);

    // Use getClipboardText() to get the text data
    // in the clipboard; also see:
    // https://doc.qt.io/squish/squish-api.html#getclipboardtext-function
    return getClipboardText();
}


function cmd_to_foreground(objOrName_cmd_window_optional)
{
    if (objOrName_cmd_window_optional == null) {
        objOrName_cmd_window_optional = {"type": "Window"};
    }

    var win = ToplevelWindow.byName(objOrName_cmd_window_optional);
    win.setForeground();
    win.setFocus();
}


function type_into_cmd_window(text, objOrName_cmd_window_optional, delay_optional=1.0)
{
    if (objOrName_cmd_window_optional == null) {
        objOrName_cmd_window_optional = {"type": "Window"};
    }

    if (delay_optional == null) {
        delay_optional = 1;
    }

    cmd_to_foreground(objOrName_cmd_window_optional);
    type(objOrName_cmd_window_optional, text);
    snooze(delay_optional);
}


function start_cmd_exe()
{
    aut = OS.getenv("WINDIR") + "\\System32\\cmd.exe";
    testSettings.setWrappersForApplication(aut, ["Windows"]);
    return startApplication('"' + aut + '" /c start /wait cmd.exe');
}
test.js

Use in other Squish Editions

Other Squish editions on Windows include some support for automating Windows applications. This level of support is fully sufficient for automating CLI windows as it is demonstrated in this article.

However, as mentioned before, a Squish for Windows license is required in addition to the license for the other Squish edition(s).

The above example code already launches cmd.exe as a Windows applications, so the code should be usable in test suites of other Squish editions.

The only point that needs additional attention is would be to switch between the other application(s) and the cmd.exe application, which is described at How to Test Multiple AUTs from a Single Test Script, Using ApplicationContext .