The issue you are experiencing is that TestComplete does not support writing to the standard output stream, even if you invoke the CLR Console.WriteLine
, you are writing to the process named tcHostingProcess.exe in which all CLR objects exist.
In order to work around this, you need a console application running that can accept messages from your TestComplete project. There are a number of ways to do this, but here is a proposed solution using TCP/IP for the necessary IPC.
In TeamCity
In the TeamCity build steps, you want the TestComplete or TestExecute process to launch without holding up the build script and then to launch a custom console application which will receive the messages from TestComplete.
start TestComplete.exe [arg1] [arg2] ...
TCConsoleHost.exe
Console Host Application
The console host program will start a TcpListener
, and once a client connects, it will read messages from the resulting NetworkStream
object and print them to the console. This program will continue until there is an error in reading from the stream (i.e. TestComplete has exited).
class Program
{
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9800);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
BinaryReader reader = new BinaryReader(stream);
while (true)
{
try
{
string message = reader.ReadString();
Console.WriteLine(message);
}
catch
{
break;
}
}
}
}
Message Client Class
Likewise, we can create a TcpClient
which can connect to our listening process and relay messages. The real trick here is to wrap this in a static class with a static constructor so that once TestComplete loads the CLR bridge, it will automatically connect and be ready to send the messages. This example has a TeamCity service message function SendMessage
which automatically formats the message (including escaping single quotes).
public static class TCServiceMessageClient
{
static BinaryWriter writer;
static NetworkStream stream;
static TCServiceMessageClient()
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 9800);
stream = client.GetStream();
writer = new BinaryWriter(stream);
}
public static void SendMessage(string message)
{
writer.Write(string.Format("##teamcity[message text='{0}'", message.Replace("'","|'")));
}
}
In TestComplete
Now, since the client will automatically connect when the CLR bridge is loaded, the only code necessary in TestComplete is:
dotNET["TCServiceMessageClient"]["TCServiceMessageClient"]["SendMessage"]("Hello TeamCity!");
Additional Notes
There are a few caveats with the above code, namely timing, reconnect, etc. A deployed solution should have better error handling of the network conditions. Additionally, it may be more desirable that the TCMessageHost application actually launches TestComplete directly with a System.Process
object so that it can more reliably wait for the application to exit.