diff --git a/renderer/render-test-case b/renderer/render-test-case
index 427eb2518ef2524be06c4d6d7fdb03aa88a34203..ef0a47ca5c5cdaec3c3138bc0fdd778fdf6e47c9 100755
--- a/renderer/render-test-case
+++ b/renderer/render-test-case
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 ###################################################################################
-# Test case renderer.
+# render-test-case: Main program to render test case files.
 # Create a HTML page from a YAML test case file.
 #
 # Copyright (C) 2018
@@ -22,174 +22,14 @@
 ###################################################################################
 
 import os
-import sys
-import yaml
 import shutil
-from jinja2 import Environment, FileSystemLoader
 from argparse import ArgumentParser
 
-from parser import parse_format
-from exceptions import ParserTypeError, ParserMissingFieldError
-
-TEMPLATE_DIR="."
-
-# This command parses each line of a list and returns a structure of the form
-# (comment, command, output) to apply the following formatting for the respective
-# sections:
-#
-# pre-conditions:
-# notes:
-# expected:
-#  - Start line with '$' for commands.
-#  - Start line with '>' for command output.
-#  - Start line with '@' to attach image.
-#  - Start line with '~' to add web link.
-#  - Everything else is a comment.
-#
-# run: steps: (only for automated tests)
-#  - Start line with '#' for comments , everything else is a command.
-#
-def parse_list(lines, automated_run=False):
-    processed_lines = []
-    for line in lines:        
-        p, c = '', ''
-        sline = line.strip()
-        if not sline:
-            continue
-
-        if automated_run:
-            if sline[0] == '#':
-                # Remove the '#' with the slice [1:]
-                processed_lines.append((sline[1:], '', '', '', ''))
-            else:
-                # Add the '$ ' in the line for the command
-                processed_lines.append(('', '$ '+sline, '', '', ''))
-        else:
-            if sline[0] == '$':
-                processed_lines.append(('', sline, '', '', ''))
-            elif sline[0] == '>':
-                processed_lines.append(('', '', sline[1:].split('\n'), '', ''))
-            elif sline[0] == '@':
-                processed_lines.append(('', '', '', sline[1:], ''))
-            elif sline[0] == '~':
-                processed_lines.append(('', '', '', '', sline[1:]))
-            else:
-                processed_lines.append((sline, '', '', '', ''))
-
-    return processed_lines
-
-def priority_color(priority):
-    return \
-        (priority == 'low'      and 'secondary') or \
-        (priority == 'medium'   and 'info')      or \
-        (priority == 'high'     and 'warning')   or \
-        (priority == 'critical' and 'danger')    or 'light'
-
-def get_template_values(testcase_data):
-    template_values = {}
-    is_automated = False
-
-    # Mandatory fields
-    metadata = testcase_data.get('metadata')
-    if not metadata:
-        print("Error: missing mandatory field metadata")
-        sys.exit(1)
-
-    for mv in ['name', 'image-type', 'image-arch', 'type',
-               'exec-type', 'priority', 'description', 'expected']:
-        value = metadata.get(mv)
-        if value:
-            if mv == 'exec-type' and value == 'automated':
-                is_automated = True
-            if mv == 'expected':
-                template_values.update({ mv : parse_list(value) })
-            else:
-                # Set the priority_color.
-                if mv == 'priority':
-                    template_values.update({ 'priority_color' :
-                                             priority_color(value) })
-                template_values.update({ mv.replace('-', '_') : value })
-        else:
-            print("Error: missing mandatory field", mv)
-            sys.exit(1)
-
-    run = testcase_data.get('run')
-    if not run:
-        print("Error: missing mandatory field run")
-        sys.exit(1)
-    else:
-        steps = run.get('steps')
-        if not steps:
-            print("Error: missing mandatory field steps for run")
-            sys.exit(1)
-        # 'is_automated' so automated tests steps are parsed differently.
-        template_values.update({ 'run_steps' :
-                                 parse_list(steps, automated_run=is_automated) })
-
-    # No mandatory fields
-    for nm in ['notes', 'format', 'maintainer', 'resources',
-               'pre-conditions', 'post-conditions']:
-        value = metadata.get(nm)
-        if value:
-            template_values.update({ nm.replace('-', '_') : parse_list(value)
-                                     if nm in ['notes', 'pre-conditions',
-                                               'post-conditions']
-                                     else value })
-
-    install = testcase_data.get('install')
-    if install:
-        deps = install.get('deps')
-        if not deps:
-            print("Error: missing mandatory field deps for install")
-            sys.exit(1)
-        template_values.update({ 'install_steps' : deps })
-        # A install.deps directive will always add a preconditions section
-        # to install the required packages using the macro to install packages.
-        template_values.update({ 'packages_list' : ' '.join(deps) })
-
-    # Macros variables
-    ostree_preconditions = metadata.get('macro_ostree_preconditions')
-    if ostree_preconditions:
-        template_values.update({ 'pkgname' : ostree_preconditions })
-
-    packages_list = metadata.get('macro_install_packages_preconditions')
-    if packages_list:
-        template_values.update({ 'packages_list' :  packages_list })
-
-    modules_preconditions = metadata.get('macro_modules_preconditions')
-    if modules_preconditions:
-        template_values.update({ 'libname' : modules_preconditions })
-
-    return template_values
-
-def generate_test_case(tc_file, directory):
-    try:
-        with open(tc_file) as testcase:
-            tc_data = yaml.safe_load(testcase)
-    except yaml.scanner.ScannerError as e:
-        print("yaml format error:", e)
-        sys.exit(1)
-
-    # Parse file to detect any syntax error.
-    print("Parsing file", tc_file)
-    try:
-        parse_format(tc_data)
-    except (ParserTypeError, ParserMissingFieldError) as error:
-        print("Error: " + str(error))
-        exit(1)
-
-    env = Environment(loader=FileSystemLoader([TEMPLATE_DIR]))
-    # Get template from environment and render it.
-    data = env.get_template('templates/index.html').render(get_template_values(tc_data))
-
-    filename = os.path.splitext(os.path.basename(tc_file))[0] + ".html"
-    print("Generating test case page", filename)
-    with open(os.path.join(directory, filename), 'w') as html_file:
-        html_file.write(data)
+from renderer import generate_test_case
 
 
 if '__main__' == __name__:
-    cli_parser = ArgumentParser(description="make_page")
+    cli_parser = ArgumentParser(description="render-test-case")
     cli_parser.add_argument('-d', '--test-case-dir',
                             help="Directory path for generated test cases")
     cli_parser.add_argument('yaml_files',
@@ -205,7 +45,7 @@ if '__main__' == __name__:
             print("Directory '{}' already exists".format(directory))
         except e:
             print("Error:", e)
-            sys.exit(1)
+            exit(1)
 
     if os.path.isfile(args.yaml_files):
         generate_test_case(args.yaml_files, directory)
diff --git a/renderer/renderer.py b/renderer/renderer.py
new file mode 100644
index 0000000000000000000000000000000000000000..8291de5f1c0e6d2c4c58eb26eae28b02e4f3354c
--- /dev/null
+++ b/renderer/renderer.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+###################################################################################
+# Test case renderer.
+# Create a HTML page from a YAML test case file.
+#
+# Copyright (C) 2018
+# Luis Araujo <luis.araujo@collabora.co.uk>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  US
+###################################################################################
+
+import os
+import yaml
+from jinja2 import Environment, FileSystemLoader
+
+from parser import parse_format
+from exceptions import ParserTypeError, ParserMissingFieldError
+
+TEMPLATE_DIR="."
+
+# This command parses each line of a list and returns a structure of the form
+# (comment, command, output) to apply the following formatting for the respective
+# sections:
+#
+# pre-conditions:
+# notes:
+# expected:
+#  - Start line with '$' for commands.
+#  - Start line with '>' for command output.
+#  - Start line with '@' to attach image.
+#  - Start line with '~' to add web link.
+#  - Everything else is a comment.
+#
+# run: steps: (only for automated tests)
+#  - Start line with '#' for comments , everything else is a command.
+#
+def parse_list(lines, automated_run=False):
+    processed_lines = []
+    for line in lines:        
+        p, c = '', ''
+        sline = line.strip()
+        if not sline:
+            continue
+
+        if automated_run:
+            if sline[0] == '#':
+                # Remove the '#' with the slice [1:]
+                processed_lines.append((sline[1:], '', '', '', ''))
+            else:
+                # Add the '$ ' in the line for the command
+                processed_lines.append(('', '$ '+sline, '', '', ''))
+        else:
+            if sline[0] == '$':
+                processed_lines.append(('', sline, '', '', ''))
+            elif sline[0] == '>':
+                processed_lines.append(('', '', sline[1:].split('\n'), '', ''))
+            elif sline[0] == '@':
+                processed_lines.append(('', '', '', sline[1:], ''))
+            elif sline[0] == '~':
+                processed_lines.append(('', '', '', '', sline[1:]))
+            else:
+                processed_lines.append((sline, '', '', '', ''))
+
+    return processed_lines
+
+def priority_color(priority):
+    return \
+        (priority == 'low'      and 'secondary') or \
+        (priority == 'medium'   and 'info')      or \
+        (priority == 'high'     and 'warning')   or \
+        (priority == 'critical' and 'danger')    or 'light'
+
+def get_template_values(testcase_data):
+    template_values = {}
+    is_automated = False
+
+    # Mandatory fields
+    metadata = testcase_data.get('metadata')
+    if not metadata:
+        print("Error: missing mandatory field metadata")
+        exit(1)
+
+    for mv in ['name', 'image-type', 'image-arch', 'type',
+               'exec-type', 'priority', 'description', 'expected']:
+        value = metadata.get(mv)
+        if value:
+            if mv == 'exec-type' and value == 'automated':
+                is_automated = True
+            if mv == 'expected':
+                template_values.update({ mv : parse_list(value) })
+            else:
+                # Set the priority_color.
+                if mv == 'priority':
+                    template_values.update({ 'priority_color' :
+                                             priority_color(value) })
+                template_values.update({ mv.replace('-', '_') : value })
+        else:
+            print("Error: missing mandatory field", mv)
+            exit(1)
+
+    run = testcase_data.get('run')
+    if not run:
+        print("Error: missing mandatory field run")
+        exit(1)
+    else:
+        steps = run.get('steps')
+        if not steps:
+            print("Error: missing mandatory field steps for run")
+            exit(1)
+        # 'is_automated' so automated tests steps are parsed differently.
+        template_values.update({ 'run_steps' :
+                                 parse_list(steps, automated_run=is_automated) })
+
+    # No mandatory fields
+    for nm in ['notes', 'format', 'maintainer', 'resources',
+               'pre-conditions', 'post-conditions']:
+        value = metadata.get(nm)
+        if value:
+            template_values.update({ nm.replace('-', '_') : parse_list(value)
+                                     if nm in ['notes', 'pre-conditions',
+                                               'post-conditions']
+                                     else value })
+
+    install = testcase_data.get('install')
+    if install:
+        deps = install.get('deps')
+        if not deps:
+            print("Error: missing mandatory field deps for install")
+            exit(1)
+        template_values.update({ 'install_steps' : deps })
+        # A install.deps directive will always add a preconditions section
+        # to install the required packages using the macro to install packages.
+        template_values.update({ 'packages_list' : ' '.join(deps) })
+
+    # Macros variables
+    ostree_preconditions = metadata.get('macro_ostree_preconditions')
+    if ostree_preconditions:
+        template_values.update({ 'pkgname' : ostree_preconditions })
+
+    packages_list = metadata.get('macro_install_packages_preconditions')
+    if packages_list:
+        template_values.update({ 'packages_list' :  packages_list })
+
+    modules_preconditions = metadata.get('macro_modules_preconditions')
+    if modules_preconditions:
+        template_values.update({ 'libname' : modules_preconditions })
+
+    return template_values
+
+def generate_test_case(tc_file, directory):
+    try:
+        with open(tc_file) as testcase:
+            tc_data = yaml.safe_load(testcase)
+    except yaml.scanner.ScannerError as e:
+        print("yaml format error:", e)
+        exit(1)
+
+    # Parse file to detect any syntax error.
+    print("Parsing file", tc_file)
+    try:
+        parse_format(tc_data)
+    except (ParserTypeError, ParserMissingFieldError) as error:
+        print("Error: " + str(error))
+        exit(1)
+
+    env = Environment(loader=FileSystemLoader([TEMPLATE_DIR]))
+    # Get template from environment and render it.
+    data = env.get_template('templates/index.html').render(get_template_values(tc_data))
+
+    filename = os.path.splitext(os.path.basename(tc_file))[0] + ".html"
+    print("Generating test case page", filename)
+    with open(os.path.join(directory, filename), 'w') as html_file:
+        html_file.write(data)