Skip to content

Commit 7fecff6

Browse files
author
Luiko Czub
committed
new TestlinkAPIClient service methods to copy test cases #17
- copyTCnewVersion(origTestCaseId, **changedAttributes) - copyTCnewTestCase(origTestCaseId, **changedAttributes) - getProjectIDByNode(a_nodeid)
1 parent feae481 commit 7fecff6

File tree

4 files changed

+158
-52
lines changed

4 files changed

+158
-52
lines changed

CHANGES.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ TestLink-API-Python-client UNDER DEVELOP v0.4.7
66

77
new service methods - copy test cases #17
88

9+
TestlinkAPIClient delivers new method to copy test cases between test suites or
10+
to create a new test case version.
11+
12+
- copyTCnewVersion(origTestCaseId, **changedAttributes)
13+
- copyTCnewTestCase(origTestCaseId, **changedAttributes)
14+
- getProjectIDByNode(a_nodeid)
15+
916
implement missing 1.9.8 api methods - TestCase #11
1017

1118
- addTestCaseToTestPlan, updateTestCase

example/TestLinkExample.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,15 @@
519519
# print "getTestCaseAttachments", response
520520
print "getTestCaseAttachments", "Sorry currently no testdata"
521521

522+
print "create new version of TC B"
523+
response = myTestLink.copyTCnewVersion(newTestCaseID_B,
524+
summary='new version of TC B', importance='1')
525+
print 'copyTCnewVersion', response
526+
print "copy TC B as TC BA into Test suite B"
527+
response = myTestLink.copyTCnewTestCase(newTestCaseID_B,
528+
testsuiteid=newTestSuiteID_A, testcasename='%sA' % NEWTESTCASE_B)
529+
print 'copyTCnewTestCase', response
530+
522531

523532
print ""
524533
print "Number of Projects in TestLink: %s " % myTestLink.countProjects()

src/testlink/testlinkapi.py

Lines changed: 100 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -145,75 +145,132 @@ def createTestCase(self, *argsPositional, **argsOptional):
145145
# ADDITIONNAL FUNCTIONS- copy test cases
146146
#
147147

148-
def _copyTC(self, origTestCaseId, duplicateaction, changedArguments):
148+
def getProjectIDByNode(self, a_nodeid):
149+
""" returns project id , the nodeid belongs to."""
150+
151+
# get node path
152+
node_path = self.getFullPath(int(a_nodeid))[a_nodeid]
153+
# get project and id
154+
a_project = self.getTestProjectByName(node_path[0])
155+
return a_project['id']
156+
157+
def copyTCnewVersion(self, origTestCaseId, **changedAttributes):
158+
""" creates a new version for test case with ID ORIGTESTCASEID
159+
160+
if the new version should differ from the original test case, changed
161+
api arguments could be defined as key value pairs.
162+
Example for changed summary and importance:
163+
- copyTCnewVersion('4711', summary = 'The summary has changed',
164+
importance = '1')
165+
"""
166+
167+
return self._copyTC(origTestCaseId, changedAttributes,
168+
duplicateaction = 'create_new_version')
169+
170+
def copyTCnewTestCase(self, origTestCaseId, **changedAttributes):
171+
""" creates a test case with values from test case with ID ORIGTESTCASEID
172+
173+
if the new test case should differ from the original test case, changed
174+
api arguments could be defined as key value pairs.
175+
Example for changed test suite and importance:
176+
- copyTCnewTestCaseVersion('4711', testsuiteid = '1007',
177+
importance = '1')
178+
"""
179+
180+
return self._copyTC(origTestCaseId, changedAttributes,
181+
duplicateaction = 'generate_new')
182+
183+
184+
def _copyTC(self, origTestCaseId, changedArgs, **options):
149185
""" creates a copy of test case with id ORIGTESTCASEID
150186
151-
DUPLICATEACTION decides, how the the test case copy (TC-copy) is
152-
inserted
153-
'generate_new': a separate new test case is created, even if name
154-
and test suite are equal
155-
'create_new_version': if the target test suite includes already a
156-
test case with the same name, a new version is created.
157-
if the target test suite includes not a test case with the defined
158-
name, a new test case with version 1 is created
159-
160-
CHANGEDARGUMENTS defines a dictionary with key value pairs, the api
161-
arguments, expected from createTestCase.
162-
Only arguments, which differ between the original and the
163-
copy must be defined here
164-
Remarks for some special keys:
165-
'testsuiteid': defines, in which test suite the TC-copy is inserted.
166-
Default is the same test suite as the original test case.
167-
'steps': must be a complete list of all steps, changed and unchanged steps
168-
Maybe its better to change the steps in a separat call using
169-
createTestCaseSteps with action='update'.
187+
returns createTestCase response for the copy
188+
189+
CHANGEDARGUMENTS defines a dictionary with api arguments, expected from
190+
createTestCase. Only arguments, which differ between TC-orig
191+
and TC-copy must be defined
192+
Remarks for some special keys:
193+
'testsuiteid': defines, in which test suite the TC-copy is inserted.
194+
Default is the same test suite as the original test case.
195+
'steps': must be a complete list of all steps, changed and unchanged steps
196+
Maybe its better to change the steps in a separat call using
197+
createTestCaseSteps with action='update'.
198+
199+
OPTIONS are optional key value pairs to influence the copy process
200+
- details see comments _copyTCbuildArgs()
170201
171202
"""
172203

173-
# (tcase_id, tcase_ext_id) = newProj(projKey, 'duplicate Test Case')
174204
# get orig test case content
175205
origArgItems = self.getTestCase(testcaseid=origTestCaseId)[0]
176-
print 'getTestCase', origArgItems
177-
# get orig test case path
178-
origPath = self.getFullPath(int(origTestCaseId))[origTestCaseId]
179-
print 'getFullPath', origPath
180-
# get orig test case project
181-
origProject = self.getTestProjectByName(origPath[0])
182-
print 'origProject', origProject
206+
# get orig test case project id
207+
origArgItems['testprojectid'] = self.getProjectIDByNode(origTestCaseId)
183208

184-
# extend origItems with some default values
185-
# testprojectid, mandatory in createTestCase
186-
origArgItems['testprojectid'] = origProject['id']
187-
origArgItems['checkduplicatedname'] = 1
188-
# origArgItems['actiononduplicatedname'] = 'create_new_version'
189-
origArgItems['actiononduplicatedname'] = duplicateaction
209+
# build args for the TC-copy
210+
(posArgValues, newArgItems) = self._copyTCbuildArgs(origArgItems,
211+
changedArgs, options)
212+
# create the TC-Copy
213+
response = self.createTestCase(*posArgValues, **newArgItems)
214+
return response
215+
216+
def _copyTCbuildArgs(self, origArgItems, changedArgs, options):
217+
""" build Args to create a new test case .
218+
ORIGARGITEMS is a dictionary with getTestCase response of an existing
219+
test case
220+
CHANGEDARGS is a dictionary with api argument for createTestCase, which
221+
should differ from these
222+
OPTIONS is a dictionary with settings for the copy process
190223
191-
# collect info, which arguments are needed from orig test case
224+
'duplicateaction': decides, how the TC-copy is inserted
225+
- 'generate_new' (default): a separate new test case is created, even
226+
if name and test suite are equal
227+
- 'create_new_version': if the target test suite includes already a
228+
test case with the same name, a new version is created.
229+
if the target test suite includes not a test case with the
230+
defined name, a new test case with version 1 is created
231+
"""
232+
233+
# collect info, which arguments createTestCase expects
192234
(posArgNames, optArgNames, manArgNames) = \
193235
self._apiMethodArgNames('createTestCase')
194236
# some argNames not realy needed
195237
optArgNames.remove('internalid')
196238
optArgNames.remove('devKey')
197239

240+
# mapping between getTestCase response and createTestCase arg names
198241
externalArgNames = posArgNames[:]
199242
externalArgNames.extend(optArgNames)
200-
externalTointernalNames = {'testcasename' : 'name', 'testsuiteid' : 'testsuite_id',
201-
'authorlogin' : 'author_login', 'execution' : 'execution_type',
202-
'order' : 'node_order'}
243+
externalTointernalNames = {'testcasename' : 'name',
244+
'testsuiteid' : 'testsuite_id', 'authorlogin' : 'author_login',
245+
'execution' : 'execution_type', 'order' : 'node_order'}
246+
247+
# extend origItems with some values needed in createTestCase
248+
origArgItems['checkduplicatedname'] = 1
249+
origArgItems['actiononduplicatedname'] = options.get('duplicateaction',
250+
'generate_new')
251+
# build arg dictionary for TC-copy with orig values
203252
newArgItems = {}
204253
for exArgName in externalArgNames:
205254
inArgName = externalTointernalNames.get(exArgName, exArgName)
206255
newArgItems[exArgName] = origArgItems[inArgName]
256+
257+
# if changed values defines a different test suite, add the correct
258+
# project id
259+
if changedArgs.has_key('testsuiteid'):
260+
changedProjID = self.getProjectIDByNode(changedArgs['testsuiteid'])
261+
changedArgs['testprojectid'] = changedProjID
207262

263+
# change orig values for TC-copy
264+
for (argName, argValue) in changedArgs.items():
265+
newArgItems[argName] = argValue
266+
267+
# separate positional and optional createTestCase arguments
208268
posArgValues = []
209269
for argName in posArgNames:
210270
posArgValues.append(newArgItems[argName])
211271
newArgItems.pop(argName)
212-
213-
print 'posArgValues', posArgValues
214-
print 'newArgItems', newArgItems
215-
response = self.createTestCase(*posArgValues, **newArgItems)
216-
print 'createTestCase' , response
272+
273+
return (posArgValues, newArgItems)
217274

218275
#
219276
# ADDITIONNAL FUNCTIONS

test/utest-offline/testlinkapi_offline_test.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,18 @@
109109
},
110110
'getFullPath' : {
111111

112-
26 : {'26' : ['TestPlan_API', 'A - First Level', 'AA - Second Level']},
112+
26 : {'26' : ['NEW_PROJECT_API', 'A - First Level', 'AA - Second Level']},
113+
4711 : {'4711' : ['OLD_PROJECT_API']},
113114
},
114115
'getTestProjectByName' : {
115-
'TestPlan_API' : {
116-
'opt': {'requirementsEnabled': 0, 'testPriorityEnabled': 1,
117-
'automationEnabled': 1, 'inventoryEnabled': 0},
116+
'NEW_PROJECT_API' : {
118117
'prefix': 'NPROAPI', 'name': 'NEW_PROJECT_API', 'color': '',
119118
'notes': 'This is a Project created with the API',
120-
'option_priority': '0',
121-
'options': 'O:8:"stdClass":4:{s:19:"requirementsEnabled";i:0;s:19:"testPriorityEnabled";i:1;s:17:"automationEnabled";i:1;s:16:"inventoryEnabled";i:0;}',
122-
'tc_counter': '2', 'option_reqs': '0', 'active': '1',
123119
'is_public': '1', 'id': '21', 'option_automation': '0'},
120+
'OLD_PROJECT_API' : {
121+
'prefix': 'OPROAPI', 'name': 'OLD_PROJECT_API', 'color': '',
122+
'notes': 'This is a Project created with the API',
123+
'is_public': '1', 'id': '2211', 'option_automation': '0'},
124124
},
125125
'createTestCase' : 'dummy response createTestCase',
126126
}
@@ -285,18 +285,51 @@ def test_getTestCaseIDByName_listResult(self):
285285
self.assertEqual('TESTCASE_AA', response[0]['name'])
286286
self.assertEqual(self.api.devKey, self.api.callArgs['devKey'])
287287

288+
def test_getProjectIDByNode(self):
289+
self.api.loadScenario(SCENARIO_A)
290+
self.assertEqual('2211', self.api.getProjectIDByNode('4711'))
291+
288292
def test__copyTC_generate_new(self):
289293
self.api.loadScenario(SCENARIO_A)
290-
self.api._copyTC('26', 'generate_new', {})
294+
self.api._copyTC('26', {}, duplicateaction = 'generate_new')
291295
self.assertEqual('generate_new',
292296
self.api.callArgs['actiononduplicatedname'])
293297

294298
def test__copyTC_create_new_version(self):
295299
self.api.loadScenario(SCENARIO_A)
296-
self.api._copyTC('26', 'create_new_version', {})
300+
self.api._copyTC('26', {}, duplicateaction = 'create_new_version')
297301
self.assertEqual('create_new_version',
298302
self.api.callArgs['actiononduplicatedname'])
299303

304+
def test__copyTC_changedArgs(self):
305+
self.api.loadScenario(SCENARIO_A)
306+
self.api._copyTC('26', {'testsuiteid' :'4711'},
307+
duplicateaction = 'generate_new')
308+
self.assertEqual('4711', self.api.callArgs['testsuiteid'])
309+
self.assertEqual('2211', self.api.callArgs['testprojectid'])
310+
311+
def test_copyTCnewVersion(self):
312+
self.api.loadScenario(SCENARIO_A)
313+
self.api.copyTCnewVersion('26', summary = 'The summary has changed',
314+
importance = '33')
315+
self.assertEqual('create_new_version',
316+
self.api.callArgs['actiononduplicatedname'])
317+
self.assertEqual('The summary has changed', self.api.callArgs['summary'])
318+
self.assertEqual('33', self.api.callArgs['importance'])
319+
self.assertEqual('TC-C', self.api.callArgs['testcasename'])
320+
self.assertEqual('25', self.api.callArgs['testsuiteid'])
321+
self.assertEqual('21', self.api.callArgs['testprojectid'])
322+
323+
324+
def test_copyTCnewTestCase(self):
325+
self.api.loadScenario(SCENARIO_A)
326+
self.api.copyTCnewTestCase('26', testsuiteid = '4711')
327+
self.assertEqual('generate_new',
328+
self.api.callArgs['actiononduplicatedname'])
329+
self.assertEqual('4711', self.api.callArgs['testsuiteid'])
330+
self.assertEqual('2211', self.api.callArgs['testprojectid'])
331+
332+
300333
if __name__ == "__main__":
301334
#import sys;sys.argv = ['', 'Test.testName']
302335
unittest.main()

0 commit comments

Comments
 (0)