Browse Source

baangt.py as Main program, removed TestRunFromExcel.py and replaced by simpler TestRunExcelImporter.py. Moved all memory to TestRunUtils.py

bernhardbuhl 4 years ago
parent
commit
0972b51a84

+ 18 - 0
README.md

@@ -4,8 +4,26 @@ This is the current release of baangt - the tool for "Basic And Advanced Next Ge
 ## Installation in a virtual environment:
 ``pip install baangt``
 
+## Installation from GIT-Repository:
+``GIT CLONE https://gogs.earthsquad.global/baangt``
+
 #Usage:
+##Run the provided Testcase
+``Python baangt.py`` will run the Testcase specified in file ``default.json``
+
+##Create your own TestStep:
+:
+```
+from baangt.TestStep import TestStepMaster
+
+class myTestStep(TestStepMaster):
+    def execute():
+        self.driver.goToURL("http://www.google.com")
+        self.driver.findByAndSetText(xpath='//input[@type='text']', value='baangt')
+        self.driver.findByAndClick(xpath='(//input[contains(@type,'submit')])[3]')
 
+```
+ That's it. All the rest is taken care of by baangt. You'll also receive a nice export file showing timing information for your TestCase.
 
 #Further reading:
 Please see latest news on http://baangt.org for community edition and http://baangt.com for corporate environments

+ 29 - 11
baangt.py

@@ -1,41 +1,59 @@
 import getopt
 import sys
 from baangt.base.TestRun import TestRun
-from baangt.base.TestRunFromExcel import TestRunFromExcel
+from baangtVIG.CustTestRun import CustTestRun
+from baangt.base.utils import utils
 
 
 def args_read(l_search_parameter):
     l_args = sys.argv[1:]
 
     try:
-        opts, args = getopt.getopt(l_args, "", ["testrun=",
-                                                "testrunfile=",
-                                                "configfile=",
-                                                ""
+        opts, args = getopt.getopt(l_args, "", ["run="
                                                 ])
     except getopt.GetoptError as err_det:
         print("Error in reading parameters:" + str(err_det))
         print_args()
-        sys.exit("Abgebrochen wegen Fehler in Aufrufparametern")
+        sys.exit("Wrong parameters - exiting")
     if opts:
         for opt, arg in opts:
             if l_search_parameter == opt:  # in ("-u", "--usage"):
                 return arg
+            if "--" + l_search_parameter == opt:
+                return arg
     return None
 
 
 def print_args():
     print("""
 Call: python baangt.py --parameters 
-       --testrun=<Existing, predefined Name of a TestRun (database or name defined inside a TestRunClass>
-       --testrunfile=<XLSX-File containing Testrun Definition>
-       --configfile=<Filename and path to a configuration file, that holds all necessary data>
+       --run=<Existing, predefined Name of a TestRun (XLSX or .JSON-File incl. Path)>
 
  Suggested for standard use:
-   python baangt.py --testrun="Franzi4711": Will run a Testrun Franzi4711 that is known in the database
-   python baangt.py --configfile="runProd.json": Will execute a Testrun as specified in runProd.json 
+   python baangt.py --run="Franzi4711.xlsx": Will run a Testrun Franzi4711.xlsx
+   python baangt.py --run="runProd.json": Will execute a Testrun as specified in runProd.json
    """)
 
+def callTestrun():
+    if ".XLSX" in testRunFile.upper():
+        CustTestRun(testRunName=utils.sanitizeFileName(testRunFile))
+    if ".JSON" in testRunFile.upper():
+        CustTestRun(testRunName=utils.sanitizeFileName(testRunFile))
+        pass
+
 
 print_args()
 
+testRunFile : str = args_read("run")
+if testRunFile:
+    print(f"Starting Testrun: {testRunFile}")
+else:
+    sys.exit("Called without Testrun definition - exiting")
+
+callTestrun()
+
+
+
+
+
+

+ 5 - 3
baangt/TestCase/TestCaseMaster.py

@@ -10,9 +10,11 @@ class TestCaseMaster:
         self.apiInstance = None
         self.numberOfParallelRuns = None
         self.testRunInstance = kwargs.get(GC.KWARGS_TESTRUNINSTANCE)
-        self.testSequence = self.testRunInstance.getSequenceByNumber(kwargs.get(GC.STRUCTURE_TESTCASESEQUENCE))
-        self.testCaseSettings = self.testRunInstance.getTestCaseByNumber(self.testSequence,
-                                                                         kwargs.get(GC.STRUCTURE_TESTCASE))
+        self.testRunUtils = self.testRunInstance.testRunUtils
+        self.testSequence = self.testRunUtils.getSequenceByNumber(testRunName=self.testRunInstance.testRunName,
+                                                                  sequence=kwargs.get(GC.STRUCTURE_TESTCASESEQUENCE))
+        self.testCaseSettings = self.testRunUtils.getTestCaseByNumber(self.testSequence,
+                                                                      kwargs.get(GC.STRUCTURE_TESTCASE))
         self.testSteps = self.testCaseSettings[2][GC.STRUCTURE_TESTSTEP]
         self.testCaseType = self.testCaseSettings[1][GC.KWARGS_TESTCASETYPE]
         self.kwargs = kwargs

+ 1 - 1
baangt/TestCaseSequence/TestCaseSequenceMaster.py

@@ -64,7 +64,7 @@ class TestCaseSequenceMaster:
                 if self.dataRecords.get(n + x):
                     logger.debug(f"starting Process and Executions {x}. Value of n+x is {n + x}, "
                                  f"Record = {str(self.dataRecords[n + x])[0:50]}")
-                    self.kwargs[GC.STRUCTURE_TESTCASESEQUENCE] = self.testSequenceData
+                    #self.kwargs[GC.STRUCTURE_TESTCASESEQUENCE] = self.testSequenceData
                     self.kwargs[GC.KWARGS_DATA] = self.dataRecords[n+x]
                     self.kwargs[GC.KWARGS_BROWSER] = browserInstances[x]
                     processes[x] = TestCaseSequenceParallel(sequenceNumber=x,

+ 6 - 4
baangt/TestSteps/TestStepMaster.py

@@ -6,7 +6,7 @@ import sys
 
 class TestStepMaster:
     def __init__(self, **kwargs):
-        self.testRun = kwargs.get(GC.KWARGS_TESTRUNINSTANCE)
+        self.testRunInstance = kwargs.get(GC.KWARGS_TESTRUNINSTANCE)
         self.testcaseDataDict = kwargs.get(GC.KWARGS_DATA)
         self.timing: Timing = kwargs.get(GC.KWARGS_TIMING)
         self.timingName = self.timing.takeTime(self.__class__.__name__, forceNew=True)
@@ -14,10 +14,12 @@ class TestStepMaster:
         self.apiSession = kwargs.get(GC.KWARGS_API_SESSION)
         self.testCaseStatus = None
         self.testStepNumber = kwargs.get(GC.STRUCTURE_TESTSTEP) # Set in TestRun by TestCaseMaster
+        self.testRunUtil = self.testRunInstance.testRunUtils
         # check, if this TestStep has additional Parameters and if so, execute
-        lSequence = self.testRun.getSequenceByNumber(kwargs.get(GC.STRUCTURE_TESTCASESEQUENCE))
-        lTestCase = self.testRun.getTestCaseByNumber(lSequence, kwargs.get(GC.STRUCTURE_TESTCASE))
-        lTestStep = self.testRun.getTestStepByNumber(lTestCase, kwargs.get(GC.STRUCTURE_TESTSTEP))
+        lSequence = self.testRunUtil.getSequenceByNumber(testRunName=self.testRunInstance.testRunName,
+                                                         sequence=kwargs.get(GC.STRUCTURE_TESTCASESEQUENCE))
+        lTestCase = self.testRunUtil.getTestCaseByNumber(lSequence, kwargs.get(GC.STRUCTURE_TESTCASE))
+        lTestStep = self.testRunUtil.getTestStepByNumber(lTestCase, kwargs.get(GC.STRUCTURE_TESTSTEP))
         self.ifActive = False
         self.ifIsTrue = True
 

+ 45 - 16
baangt/base/TestRun.py

@@ -2,27 +2,32 @@ from baangt.base.BrowserHandling import BrowserDriver
 from baangt.base.ApiHandling import ApiHandling
 from baangt.base.ExportResults import ExportResults
 from baangt.base.Timing import Timing
+from baangt.base.utils import utils
 from baangt.base import GlobalConstants as GC
+from baangt.base.TestRunExcelImporter import TestRunExcelImporter
+from baangt.base.TestRunUtils import TestRunUtils
 import logging
 import sys
+import json
 
 logger = logging.getLogger("pyC")
 
 
 class TestRun:
-    def __init__(self, testRunName, browserName=None):
-        self.testRunName = testRunName
-        self.testrunAttributes = None
+    def __init__(self, testRunName):
+        # self.testRunAttributes = {}
         self.browser = {}
         self.apiInstance = None
-        self.dataRecords = {}
         self.testType = None
-        self.timing = Timing()
         self.kwargs = {}
-        if browserName:
-            # Overwrites the Browser-definition of the testcase
-            self.testrunAttributes[self.testRunName][GC.KWARGS_BROWSER] = browserName
+        self.dataRecords = {}
+
+        self.testRunName, self.testRunFileName = TestRun._sanitizeTestRunNameAndFileName(testRunName)
+        self.timing = Timing()
+        self.testRunUtils = TestRunUtils()
         self._initTestRun()
+        self._loadJSONTestRunDefinitions()
+        self._loadExcelTestRunDefinitions()
         self.executeTestRun()
         self.tearDown()
 
@@ -39,7 +44,8 @@ class TestRun:
         ExportResults(**self.kwargs)
 
     def getAllTestRunAttributes(self):
-        return self.testrunAttributes[self.testRunName][GC.KWARGS_TESTRUNATTRIBUTES]
+        return self.testRunUtils.getCompleteTestRunAttributes(self.testRunName)
+        # return self.testRunAttributes[self.testRunName][GC.KWARGS_TESTRUNATTRIBUTES]
 
     def getBrowser(self, browserInstance=1, browserName=None, browserAttributes=None):
         if browserInstance not in self.browser.keys():
@@ -70,7 +76,7 @@ class TestRun:
             Start TestcaseSequence
         """
         self.executeDictSequenceOfClasses(
-            self.testrunAttributes[self.testRunName][GC.KWARGS_TESTRUNATTRIBUTES][GC.STRUCTURE_TESTCASESEQUENCE],
+            self.testRunUtils.getCompleteTestRunAttributes(self.testRunName)[GC.STRUCTURE_TESTCASESEQUENCE],
             counterName=GC.STRUCTURE_TESTCASESEQUENCE)
 
     def executeDictSequenceOfClasses(self, dictSequenceOfClasses, counterName, **kwargs):
@@ -98,14 +104,26 @@ class TestRun:
     def _initTestRun(self):
         pass
 
-    def getSequenceByNumber(self, sequence):
-        return self.testrunAttributes[self.testRunName][GC.KWARGS_TESTRUNATTRIBUTES][GC.STRUCTURE_TESTCASESEQUENCE].get(sequence)
+    def _loadJSONTestRunDefinitions(self):
+        if not self.testRunFileName:
+            return
 
-    def getTestCaseByNumber(self, sequence, testcaseNumber):
-        return sequence[1][GC.STRUCTURE_TESTCASE][testcaseNumber]
+        if ".JSON" in self.testRunFileName.upper():
+            logger.info(f"Reading Definition from {self.testRunFileName}")
+            with open(self.testRunFileName) as json_file:
+                data = json.load(json_file)
+                data = utils.replaceAllGlobalConstantsInDict(data)
+                self.testRunUtils.setCompleteTestRunAttributes(testRunName=self.testRunName,
+                                                               testRunAttributes=data)
 
-    def getTestStepByNumber(self, testCase, testStepNumber):
-        return testCase[2][GC.STRUCTURE_TESTSTEP].get(testStepNumber)
+    def _loadExcelTestRunDefinitions(self):
+        if not self.testRunFileName:
+            return
+
+        if ".XLSX" in self.testRunFileName.upper():
+            logger.info(f"Reading Definition from {self.testRunFileName}")
+            lExcelImport = TestRunExcelImporter(FileNameAndPath=self.testRunFileName, testRunUtils=self.testRunUtils)
+            lExcelImport.importConfig()
 
     @staticmethod
     def __dynamicImportClasses(fullQualifiedImportName):
@@ -132,3 +150,14 @@ class TestRun:
             sys.exit("Critical Error in Class import - can't continue. "
                      "Please maintain proper classnames in Testrundefinition.")
         return retClass
+
+    @staticmethod
+    def _sanitizeTestRunNameAndFileName(TestRunNameInput):
+        if ".XLSX" in TestRunNameInput.upper() or ".JSON" in TestRunNameInput.upper():
+            lRunName = utils.extractFileNameFromFullPath(TestRunNameInput)
+            lFileName = TestRunNameInput
+        else:
+            lRunName = TestRunNameInput
+            lFileName = None
+
+        return lRunName, lFileName

+ 35 - 33
baangt/base/TestRunFromExcel.py

@@ -1,42 +1,47 @@
-from baangt.base.TestRun import TestRun
 from baangt.base.utils import utils
+from baangt.base.TestRunUtils import TestRunUtils
 import baangt.base.GlobalConstants as GC
 import baangt.base.CustGlobalConstants as CGC
 import xlrd
 import logging
 
-logger = logging.getLogger("pyC")
 
-class TestRunFromExcel(TestRun):
-    def __init__(self, lExcelDefinitionFile:str):
-        self.excelFile = xlrd.open_workbook(lExcelDefinitionFile)
-        self.fileAndPathName = lExcelDefinitionFile
-        self.fileName = utils.extractFileNameFromFullPath(self.fileAndPathName)
-        if not self.excelFile:
-            raise BaseException(f"ConfigFile not found {lExcelDefinitionFile}")
-        super().__init__(testRunName=self.fileName)
+class TestRunExcelImporter:
+    def __init__(self, FileNameAndPath, testRunUtils: TestRunUtils):
+        # self.testRunAttributes = testRunUtils.testRunAttributes
+        self.testRunUtils = testRunUtils
+        try:
+            self.excelFile = xlrd.open_workbook(FileNameAndPath)
+        except FileNotFoundError as e:
+            raise BaseException(f"File not found - exiting {e}")
+
+        self.fileName = utils.extractFileNameFromFullPath(FileNameAndPath)
+
+    def importConfig(self):
+        self._initTestRun()
+        return self.testRunUtils.getCompleteTestRunAttributes(self.fileName)
 
     def _initTestRun(self):
-        self.testrunAttributes = {
+        self.testRunUtils.testRunAttributes = {
             self.fileName: {
                 GC.KWARGS_TESTRUNATTRIBUTES: {
             },},}
-        testrunAttributes = self.testrunAttributes[self.fileName][GC.KWARGS_TESTRUNATTRIBUTES]
+        testRunAttributes = self.testRunUtils.testRunAttributes[self.fileName][GC.KWARGS_TESTRUNATTRIBUTES]
 
         xlsTab = self._getTab("TestRun")
-        testrunAttributes[GC.EXPORT_FORMAT] = {GC.EXPORT_FORMAT: self._getValueFromList(xlsTab=xlsTab,
+        testRunAttributes[GC.EXPORT_FORMAT] = {GC.EXPORT_FORMAT: self._getValueFromList(xlsTab=xlsTab,
                                                                                         searchField=GC.EXPORT_FORMAT)}
         xlsTab = self._getTab("ExportFieldList")
-        testrunAttributes[GC.EXPORT_FORMAT][GC.EXP_FIELDLIST] = self._getRowAsList(xlsTab)
+        testRunAttributes[GC.EXPORT_FORMAT][GC.EXP_FIELDLIST] = self._getRowAsList(xlsTab)
 
-        testrunAttributes[GC.STRUCTURE_TESTCASESEQUENCE] = {}
-        testrunSequence = testrunAttributes[GC.STRUCTURE_TESTCASESEQUENCE]
+        testRunAttributes[GC.STRUCTURE_TESTCASESEQUENCE] = {}
+        testrunSequence = testRunAttributes[GC.STRUCTURE_TESTCASESEQUENCE]
         xlsTab = self._getTab("TestCaseSequence")
         lSequenceDict = self.getRowsWithHeadersAsDict(xlsTab=xlsTab)
         for key, sequence in lSequenceDict.items():
             testrunSequence[key] = [sequence["SequenceClass"], {}]
             for field, value in sequence.items():
-                testrunAttributes[GC.STRUCTURE_TESTCASESEQUENCE][key][1][field] = value
+                testRunAttributes[GC.STRUCTURE_TESTCASESEQUENCE][key][1][field] = value
 
         xlsTab = self._getTab("TestCase")
         lTestCaseDict = self.getRowsWithHeadersAsDict(xlsTab=xlsTab)
@@ -64,23 +69,23 @@ class TestRunFromExcel(TestRun):
         xlsTab = self._getTab("TestStepExecution")
         lExecDict = self.getRowsWithHeadersAsDict(xlsTab=xlsTab)
         for key, execLine in lExecDict.items():
-            lSequence = self.getSequenceByNumber(execLine["TestCaseSequenceNumber"])
-            lTestCase = self.getTestCaseByNumber(sequence = lSequence,
+            lSequence = self.testRunUtils.getSequenceByNumber(testRunName=self.fileName,
+                                                              sequence=execLine["TestCaseSequenceNumber"])
+            lTestCase = self.testRunUtils.getTestCaseByNumber(sequence = lSequence,
                                                  testcaseNumber=execLine["TestCaseNumber"])
-            lTestStep = self.getTestStepByNumber(testCase=lTestCase,
+            lTestStep = self.testRunUtils.getTestStepByNumber(testCase=lTestCase,
                                                  testStepNumber=execLine["TestStepNumber"])
             # if this TestStep is still just a String, then it needs to be converted into a List with Dict
             # to hold the TestexecutionSteps in this Dict.
             if isinstance(lTestStep, str):
                 lTestCase[2][GC.STRUCTURE_TESTSTEP][execLine["TestStepNumber"]] = \
                     [lTestStep, {GC.STRUCTURE_TESTSTEPEXECUTION: {}}]
-                lTestStep = self.getTestStepByNumber(testCase=lTestCase,
+                lTestStep = self.testRunUtils.getTestStepByNumber(testCase=lTestCase,
                                                      testStepNumber=execLine["TestStepNumber"])
 
             lTestStep[1][GC.STRUCTURE_TESTSTEPEXECUTION][execLine["TestStepExecutionNumber"]] = {}
             for lkey, value in execLine.items():
                 lTestStep[1][GC.STRUCTURE_TESTSTEPEXECUTION][execLine["TestStepExecutionNumber"]][lkey] = value
-                pass
 
     def getRowsWithHeadersAsDict(self, xlsTab):
         lRetDict = {}
@@ -88,39 +93,36 @@ class TestRunFromExcel(TestRun):
         for row in range(1, xlsTab.nrows):
             lRetDict[row] = {}
             for col in range(0, xlsTab.ncols):
-                lRetDict[row][xlsTab.cell_value(0,col)] = self.sanitizeFieldValue(xlsTab.cell_value(row,col))
+                lRetDict[row][xlsTab.cell_value(0,col)] = self.replaceFieldValueWithValueOfConstant(xlsTab.cell_value(row, col))
         return lRetDict
 
     def _getRowAsList(self, xlsTab, colNumber=0):
         l_fields = []
         for row in range(1, xlsTab.nrows):
-            l_fields.append(self.sanitizeFieldValue(xlsTab.cell_value(row, colNumber)))
+            l_fields.append(self.replaceFieldValueWithValueOfConstant(xlsTab.cell_value(row, colNumber)))
         return l_fields
 
     def _getValueFromList(self, xlsTab, searchField):
         # Searches for Value in Column 1 and returns Value from Column 2 if found.
         for row in range(1, xlsTab.nrows):
             if xlsTab.cell_value(row,1) == searchField:
-                return self.sanitizeFieldValue(xlsTab.cell_value(row,2))
+                return self.replaceFieldValueWithValueOfConstant(xlsTab.cell_value(row, 2))
 
     def _getTab(self, tabName):
         worksheet = self.excelFile.sheet_by_name(tabName)
         return worksheet
 
-    def sanitizeFieldValue(self, value):
+    def replaceFieldValueWithValueOfConstant(self, value):
         if isinstance(value, float):
             if value % 1 == 0:
                 return int(value)
         elif isinstance(value, int):
             return value
 
-        #value = value.replace("'", "") # not possible due to XPATH-Notation in some fields
-        #value = value.replace('"', "") # not possible due to XPATH-Notation in some fields.
         value = value.strip()
-        if value[0:3] == "GC." or value[0:4] == "CGC.":
-            # value = globals()[value] --> Doesn't work
-            # value = getattr(value.split(".")[0], value.split(".")[1]) --> Doesn't work
-            value = getattr(globals()[value.split(".")[0]], value.split(".")[1])
-        return value
+        value = utils.replaceFieldValueWithValueOfConstant(value)
 
+        if value[0:4] == "CGC.":
+            value = getattr(globals()[value.split(".")[0]], value.split(".")[1])
 
+        return value

+ 20 - 0
baangt/base/TestRunUtils.py

@@ -0,0 +1,20 @@
+import baangt.base.GlobalConstants as GC
+
+class TestRunUtils():
+    def __init__(self):
+        self.testRunAttributes = {}
+
+    def setCompleteTestRunAttributes(self, testRunName:str, testRunAttributes: dict):
+        self.testRunAttributes[testRunName] = testRunAttributes
+
+    def getCompleteTestRunAttributes(self, testRunName):
+        return self.testRunAttributes[testRunName][GC.KWARGS_TESTRUNATTRIBUTES]
+
+    def getSequenceByNumber(self, sequence, testRunName):
+        return self.testRunAttributes[testRunName][GC.KWARGS_TESTRUNATTRIBUTES][GC.STRUCTURE_TESTCASESEQUENCE].get(sequence)
+
+    def getTestCaseByNumber(self, sequence, testcaseNumber):
+        return sequence[1][GC.STRUCTURE_TESTCASE][testcaseNumber]
+
+    def getTestStepByNumber(self, testCase, testStepNumber):
+        return testCase[2][GC.STRUCTURE_TESTSTEP].get(testStepNumber)

+ 48 - 1
baangt/base/utils.py

@@ -1,4 +1,5 @@
 from datetime import datetime
+import baangt.base.GlobalConstants as GC
 import ntpath
 
 class utils:
@@ -14,4 +15,50 @@ class utils:
     @staticmethod
     def extractFileNameFromFullPath(fileAndPathName):
         return ntpath.basename(fileAndPathName)
-        pass
+        pass
+
+    @staticmethod
+    def sanitizeFileName(value):
+        value = value.replace("'", "")
+        value = value.replace('"', "")
+
+        return value
+
+    @staticmethod
+    def replaceFieldValueWithValueOfConstant(value):
+        """
+        If a String reference to global Constant (e.g. GC.BROWSER_FF) is
+        given, this function will replace it with the actual value (e.g. FIREFOX)
+        """
+        if value[0:3] == "GC.":
+            value = getattr(globals()[value.split(".")[0]], value.split(".")[1])
+        return value
+
+    @staticmethod
+    def replaceAllGlobalConstantsInDict(lDict : dict):
+        lDictOut = {}
+        for key, value in lDict.items():
+            lKey = utils.replaceFieldValueWithValueOfConstant(key)
+            if isinstance(value, str):
+                lDictOut[lKey] = utils.replaceFieldValueWithValueOfConstant(value)
+            elif isinstance(value, dict):
+                lDictOut[lKey] = utils.replaceAllGlobalConstantsInDict(value)
+            elif isinstance(value, list):
+                lDictOut[lKey] = utils._loopList(value)
+            else:
+                lDictOut[lKey] = value
+
+        return lDictOut
+
+    @staticmethod
+    def _loopList(listIn):
+        listOut = []
+        for item in listIn:
+            if isinstance(item, str):
+                item = utils.replaceFieldValueWithValueOfConstant(item)
+            elif isinstance(item,dict):
+                item = utils.replaceAllGlobalConstantsInDict(item)
+            elif isinstance(item,list):
+                item = utils._loopList(item)
+            listOut.append(item)
+        return listOut

+ 1 - 1
setup.py

@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
 
 setuptools.setup(
     name="baangt", # Replace with your own username
-    version="2020.1.0b2",
+    version="2020.1.0b3",
     author="Bernhard Buhl",
     author_email="buhl@buhl-consulting.com.cy",
     description="Basic And Advanced NextGeneration Testing",