I've created a very complex script using Python3 and YAML (I keep all the configurations in YAML) that in effect tests all potential file downloads for my environment. Sort of end to end test. Due to specific patenting behind, I can't share too much of code, but I am having around 37 different property combinations that download a different file, and each file can be downloaded as zip/gzip, or CSV/XML, so technically 37 X 4 is the total number of my files. To make it "simpler", I need to check that file with license key for combination 1, works only for 1, not for 2-37, and with it we are growing to a relatively big number of tests, currently around 380 in the script, 70ish being happy path tests, and the rest negative tests.
This script was so far run manually, and I'm now trying to convert it and automate with Jenkins, where I'd need to print out some nice report.
I have the following script structure in one big .py file (760 lines):
- a few methods used to read configurations from YAML
- a few methods building URLs reusing config from YAML for files that will be downloaded
- a few methods using requests to download files and their MD5s using built URLs
the method that executes a single test that then compares calculated MD5 from downloaded file and MD5 that is served from the server
def executeTest(testName,conf, compareFlag="", fromThread=""): if compareFlag=="Compare": testPrintableName = getTestName(conf, testName) urlForFile = testUrlBuilder(conf, testName, "") urlForMD5 = testUrlBuilder(conf, testName, "MD5") if printHeadersAndPaths: print (urlForFile) timeDlStart = time.time() filePath = getFile(urlForFile, "") timePassed = time.time() - timeDlStart #print (timePassed) if printHeadersAndPaths: print (urlForMD5) md5Path = getFile(urlForMD5, "") #print(filePath) #print(md5Path) if ((filePath == "Site Maintanance") and (md5Path is not None)): print(testPrintableName + " Attempted to get file from site under Maintanance") elif ((filePath is not None) and (md5Path is not None)): if ((filePath == "Invalid Index Attempt") and (md5Path == "Invalid Index Attempt")): print(testPrintableName + " Attempted to get wrong file with license for different Index type") elif ((filePath == "Invalid Licence Attempt") and (md5Path == "Invalid Licence Attempt")): print(testPrintableName + " Attempted to get wrong file with invalid licence (eg Beta licence to get Alpha file)") elif ((filePath == "Invalid LicenSe Attempt") and (md5Path == "Invalid LicenSe Attempt")): print(testPrintableName + " Attempted to get wrong file with invalid license (eg Beta license to get Alpha file)") elif ((filePath == "Invalid Key Attempt") and (md5Path == "Invalid Key Attempt")): print(testPrintableName + " Attempted to get wrong file with license for different File Type") elif ((filePath == "Site Maintanance") and (md5Path == "Site Maintanance")): print(testPrintableName + " Attempted to get from site under Maintanance") elif ((filePath == "Nothing") and (md5Path == "Nothing")): print(testPrintableName + " Attempted to get special data - where we return Nothing") elif ((filePath == "Invalid License Gama At Alpha") and (md5Path == "Invalid License Attempt At Gama")): print(testPrintableName + " Attempted to get Gama Data with wrong license") else: cal = calculateMD5(filePath) ff = readMD5fromFile(md5Path) if (cal.strip() != ff.strip()): print ("Test "+ testPrintableName + "MAYBE FAILED - Calculated MD5 " + str(cal) + " does not match the one grabbed from file " + str(ff) + fromThread) else: print ("Test " + testPrintableName + " PASSED " + lastModifiedComparedToNow(lastModified, requestTime) + " in " + str(timePassed) + " seconds " + fromThread) else: if (filePath is not None and filePath != "Invalid Index Attempt"): print ("Test "+ testPrintableName + "FAILED - " + "File was not downloaded properly " + fromThread) if (md5Path is None and md5Path != "Invalid Index Attempt"): print ("Test "+ testPrintableName + "FAILED - " + "MD5 file was not downloaded properly " + fromThread) else: pass
a load of methods that execute set of tests by name grouped in meaningful methods
def happyPathsPOIMaps(conf): executeTest("POIMapCsvCommaZip", conf, "Compare") executeTest("POIMapCsvSemicolonZip", conf, "Compare") executeTest("POIMapCsvPipeZip", conf, "Compare") executeTest("POIMapCsvXMLZip", conf, "Compare") executeTest("POIMapCsvCommaGz", conf, "Compare") executeTest("POIMapCsvSemicolonGz", conf, "Compare") executeTest("POIMapCsvPipeGz", conf, "Compare") executeTest("POIMapCsvXMLGz", conf, "Compare" )
Each test (again, coming from YAML) contains all the parameters used in building URL for certain file type, that is then tested. Tests in YAML look like this:
#format: 'testName,environment,licenseNameToTest,serverUrlExtendionToUse,CompressionFormat,FileFormat,DataFileType,MD5,Date'
POIMapCsvCommaZip: '"Test Get POI Map",testsrv,POIMap, getPOIMap, zip,xml, , '
YAML contains all servers and test combinations, and it's currently at 500 lines.
And now, finally, my questions:
- Is there any good testing framework that I could use with python 3 to rewrite upper "executeTest" method and get decent reporting
- Is there a more pythonic way how to test such described test cases (using assertions?)
- Is there a way to split YAML to multiple files and load them all "as one file" without actually merging them (like sepparate server configs from happy path tests and negative tests, and then just have at the beginning of YAML - load a.yml,b.yml...
I'm open to suggestions, this does the job at the moment, but I have a feeling that it is overly complex and that there must be a way to make it simpler. Maybe separate methods that are tested in a separate file?
Thanks in advance for not closing it as not constructive enough.