30
30
import io
31
31
import inspect
32
32
import time
33
+ import random
33
34
from pathlib import Path
34
35
import asyncio
35
36
from pyscript import RUNNING_IN_WORKER
@@ -120,6 +121,28 @@ def parse_traceback_from_exception(ex):
120
121
return "\n " .join (result )
121
122
122
123
124
+ def shuffle (a_list ):
125
+ """
126
+ Shuffle a list, in place.
127
+
128
+ This function is needed because MicroPython does not have a random.shuffle
129
+ function.
130
+
131
+ It falls back to random.shuffle if using CPython, otherwise it uses a
132
+ simple implementation of the Fisher-Yates in-place shuffle algorithm.
133
+
134
+ Context:
135
+
136
+ https://stackoverflow.com/questions/73143243/are-there-any-alternatives-for-the-python-module-randoms-shuffle-function-in
137
+ """
138
+ if hasattr (random , "shuffle" ):
139
+ random .shuffle (a_list )
140
+ else :
141
+ for i in range (len (a_list ) - 1 , 0 , - 1 ):
142
+ j = random .randrange (i + 1 )
143
+ a_list [i ], a_list [j ] = a_list [j ], a_list [i ]
144
+
145
+
123
146
class TestCase :
124
147
"""
125
148
Represents an individual test to run.
@@ -274,7 +297,7 @@ async def print(self, text):
274
297
await asyncio .sleep (0 )
275
298
print (text , end = "" , flush = True )
276
299
277
- async def run (self ):
300
+ async def run (self , randomize = False ):
278
301
"""
279
302
Run each TestCase instance for this module. If a setup or teardown
280
303
exists, these will be evaluated immediately before and after the
@@ -284,6 +307,8 @@ async def run(self):
284
307
for each skipped test.
285
308
"""
286
309
print (f"\n { self .path } : " , end = "" )
310
+ if randomize :
311
+ shuffle (self ._tests )
287
312
for test_case in self .tests :
288
313
if self .setup :
289
314
if is_awaitable (self .setup ):
@@ -466,12 +491,16 @@ async def run(*args, **kwargs):
466
491
print ("Running in worker: \033 [1m" , RUNNING_IN_WORKER , "\033 [0m" )
467
492
targets = []
468
493
pattern = kwargs .get ("pattern" , "test_*.py" )
494
+ randomize = kwargs .get ("random" , False )
495
+ print ("Randomize test order: \033 [1m" , randomize , "\033 [0m" )
469
496
for arg in args :
470
497
if isinstance (arg , str ):
471
498
targets .append (arg )
472
499
else :
473
500
raise ValueError (f"Unexpected argument: { arg } " )
474
501
test_modules = discover (targets , pattern )
502
+ if randomize :
503
+ shuffle (test_modules )
475
504
module_count = len (test_modules )
476
505
test_count = sum ([len (module .tests ) for module in test_modules ])
477
506
print (
@@ -483,7 +512,7 @@ async def run(*args, **kwargs):
483
512
passed_tests = []
484
513
start = time .time ()
485
514
for module in test_modules :
486
- await module .run ()
515
+ await module .run (randomize )
487
516
for test in module .tests :
488
517
if test .status == FAIL :
489
518
failed_tests .append (test )
@@ -542,6 +571,7 @@ async def run(*args, **kwargs):
542
571
"platform" : sys .platform ,
543
572
"version" : sys .version ,
544
573
"running_in_worker" : RUNNING_IN_WORKER ,
574
+ "randomize" : randomize ,
545
575
"passes" : [test .as_dict for test in passed_tests ],
546
576
"fails" : [test .as_dict for test in failed_tests ],
547
577
"skipped" : [test .as_dict for test in skipped_tests ],
0 commit comments