Applying Model Controller Testsuite to test automation

You probably know MVC. How about MCT?

Model–view–controller is commonly used for developing software that divides an application into three interconnected parts. This is done to separate internal representations of information from the ways information is presented to and accepted from the user. The MVC design pattern decouples these major components allowing for efficient code reuse and parallel development.

In order to take advantage of the benefits MVC provides, you need to implement this clear separation of concerns in your test framework as well. This article describes an approach to test automation inspired by a known development design pattern; that being Model Controller Testsuite (MCT) and describes how it can be adapted to make your automation code more stable and maintainable.

How to use MCT

As mentioned previously, we must take advantage of the benefits MVC to implement our test automation framework. With this regard, we propose MCT as a design pattern for automation testing, which is an acronym for:

  • Model: Data, resources, variables in env, tool
  • Controller: Keywords, libraries
  • Testsuite: Test cases


The Model has the same function as it does in the MVC; it provides complete variable objects to the Controller layer, such as data, tools, and static files so you can have reliable and maintainable data resource to test against. This layer contains only the functionalities to read and update test data or use tools. The data provided by the model can range from variables by country or variables by testing environment and the ones generated by user customized tools.


The Controller handles the interactions between your test cases and the Model layer. The controller layer is responsible only for providing functions or libraries for the overall test architecture. It gets data or information created by the tool or from the model layer, tests the given data, and returns the outcome for the test cases. You can use the POM (Page Object Model) or customized library with the controller layer.

Assume you are automating website testing using Selenium webdriver. In this context, the controller layer contains the Page objects designed and developed by QA engineers, and even provide a library of custom APIs, if required. The controller layer handles all the logic involved in interacting with test cases and will deliver data from the model to the testsuite layer so we can perform our tests.


The Testsuite layer handles only the testing scenarios. Regardless whether you are an engineer or a project manager, you only need to provide test specification or a set of test cases generated from the test requirements. You do not need to consider how to implement logic because you only need to know if the test result is what you expected or not.

Example of MCT

Let’s assume we have a test case that requires logging into LINE TODAY and we are trying to see if after a successful login the user’s profile thumbnail is displayed in the top right corner of the page.

LINE TODAY before and after logging in

For this case we need to have the following three prepared:


The model provides us a test variables containing test URL, username, password and display name. The model layer for our LINE TODAY example contains:

global_vars = {
    "USERNAME": "user",
    "PASSWORD": "passw0Rd",

tw_variables = {
    "COUNTRY": "TW",
    "TODAY": ""
    "CATEGORIES": [u"國內", u"娛樂", u"生活", u"鄉民", u"國際"],
id_variables = {
    "COUNTRY": "ID",
    "TODAY": ""
    "CATEGORIES": ["News", "Showbiz", "Sports", "Life"],


The controller provides various libraries that can be used by many test cases. You can see in the code below that the design pattern applied is that of PageObject model. The functionality classes (PageObjects) in this design represent a logical relationship between the pages of the website.

from selenium import webdriver
class LoginPage(self):
    browser = webdriver.Chrome()

    def click_login_entrance(self):
        """Click the login entrance"""

    def enter_username(self, username):
        """Enter the given string into the username field"""
        browser.input_text(self.locator.username, username)

    def enter_password(self,password):
        """Enter the given string into the password field"""
        browser.input_text(self.locator.password, password)

    def click_the_submit_button(self):
        """Click the submit button, and wait for the page to reload"""


We want to customize the function for testing purposes. QA engineers can build up a user-defined library, which can make up the insufficiency of built-in libraries. For example, suppose we are to test the “like” feature to an article. The built-in library does not provide a function to click a like button endlessly. So, in such case, we can use a user-defined library to provide the add_liked_to_article function as shown below.

import requests

class SampleCodeAPI:

    def __init__(self):

    def add_liked_to_article(self, article_id, like_type, cookies):

        api_url = '{api_url}/like/add'.format(api_url=self.api_url)

        payload = {
            "article": article,
            "country": country,
            "likeType": like_type

        res =, headers={"Cookie": cookies}, json=payload)

            return res.json()
            ResponseError("Response error")


All you have to do with the Testsuite layer is to define test cases. QA engineers can focus on creating test cases and verifying business logics. Project members without engineer background can write up business logic as shown below. This means anyone can participate in the testing process.

*** Test Cases ***
    Given User go to LINE TODAY
    When Login with valid credentials
    Then Login as a normal user

At LINE Taiwan, we used BDD (Behavior-driven Development) to create our test cases, which helps engineers to communicate within the scrum team, with non-engineers and business partners, and establish a clear consensus between the members.

Wrapping Up

Applying the Model Controller Testsuite (MCT) design pattern with layered structure in your test automation framework allows you to stay very flexible when it comes to changes in test environment and infrastructure. Traditionally tests contained a lot of hard-coded test data, making changes quite costly. Once you adapt MCT design pattern, it would gradually bring you to lower maintenance cost and a lot of reusable code.

Related Post