Fuzzing 
Fuzzing is a technique for testing software that involves providing invalid, unexpected, or random data as inputs to a computer program.
Introduction 
The Woke testing framework provides a FuzzTest class that can be used to write fuzz tests.
A FuzzTest can be run using the run method with two required arguments:
class  CounterTest ( FuzzTest ): 
... 
CounterTest () . run ( sequences_count = 10 ,  flows_count = 100 ) 
The first argument specifies the number of test sequences to be executed.
A sequence is an independent test case - all connected chains are reset after each sequence.
Each sequence consists of a given number of flows. A flow is an atomic test step that is executed in a test sequence.
The FuzzTest class provides two properties, sequence_num and flow_num, that can be used to obtain the current sequence and flow numbers, both starting from 0.
Flows 
A flow is a single test step that is executed in a test sequence. Flows are defined using the @flow decorator:
@flow ( precondition = lambda  self :  self . count  >  0 ) 
def  flow_decrement ( self )  ->  None : 
self . counter . decrement ( from_ = random_account ()) 
self . count  -=  1 
Flow functions must be defined inside a test class that inherits from FuzzTest.
The @flow decorator accepts the following keyword arguments:
Argument 
Description 
 
 
weightweight defining probability of the flow being executed in a test sequence; defaults to 100 
 
max_timesmaximum number of times the flow can be executed in a test sequence; defaults to None 
 
preconditionfunction that accepts a single argument self and returns a boolean value; the flow is executed only if the precondition is True 
 
 
How flow weights work
If a flow has a weight of 100 and another flow has a weight of 50, the first flow will be executed twice as often as the second flow.
@flow ( weight = 100 ) 
def  flow_1 ( self )  ->  None : 
... 
@flow ( weight = 50 ) 
def  flow_2 ( self )  ->  None : 
... 
That means that the probability of flow_1 being executed is 100 / (100 + 50) = 2/3 and the probability of flow_2 being executed is 50 / (100 + 50) = 1/3.
 
Invariants 
An invariant is a test that is executed after each flow in a test sequence. Invariants are defined using the @invariant decorator:
@invariant ( period = 10 ) 
def  invariant_count ( self )  ->  None : 
assert  self . counter . count ()  ==  self . count 
An optional period argument can be passed to the @invariant decorator. If specified, the invariant is executed only after every period flows.
Execution hooks 
Execution hooks are functions that are executed during the FuzzTest lifecycle. This is the list of all available execution hooks:
pre_sequence(self) - executed before each test sequencepre_flow(self, flow: Callable) - executed before each flow, accepts the flow function to be executed as an argumentpost_flow(self, flow: Callable) - executed after each flow, accepts the flow function that was executed as an argumentpre_invariants(self) - executed before each set of invariantspre_invariant(self, invariant: Callable) - executed before each invariant, accepts the invariant function to be executed as an argumentpost_invariant(self, invariant: Callable) - executed after each invariant, accepts the invariant function that was executed as an argumentpost_invariants(self) - executed after each set of invariantspost_sequence(self) - executed after each test sequence 
The whole FuzzTest lifecycle is visualized in the following diagram:
  
  eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1d6XLiSpb+30/hqP7TXHUwMDFk06ZzXzp6Ylx1MDAwMm9cdTAwMThcdTAwMWIvXHUwMDE4g5fpXHUwMDBlXHUwMDA3i1xmMoswizF03Fx1MDAxN5l/82rzJJOJy6AlJVx1MDAwNFx1MDAxNpi6XHJxo25cdTAwMTUgIaXOd75zTp7lX3/Y2/sxXHUwMDE4d61cdTAwMWZ/2/thvVfLLbvWK49+/EW//2b1+rbTUVx1MDAxZqHpv/vOsFedfrMxXHUwMDE4dPt/++tf50ekqk774yirZbWtzqCvvvff6t97e/+a/qk+sWv62MvLaveB9uFzpV2lrMJcdTAwMDanJYynh06/9HkxPas6KHfqLWv+0bt6n0My+/dYX1x1MDAxOcWzf4/s2qCh3sOQp4DrXHUwMDA1Z99oWHa9MVBfXHUwMDExPCU9r9lXPn7zb3tg9k5/0HOa1qHTcnr6wv74cdL5ZVXK1Wa951xmO7XZd1x1MDAwNr1yp98t99Q6zL/3bLdahcG49bGC5Wpj2HPd3Mev3P28XHUwMDA16Ht/dlxc31HrPT9K/Wy90bH6fc8xTrdcXLVcdTAwMDd6eSCY34e+xm62Nn0w/3SfoVP7eYbOsNWa/7Bl6edFXHUwMDEwI0RcdTAwMDA0X+a5WFDJ/e9eOp2piECBuEBIgPnK2v0jJVx1MDAxYoPpWZ/Lrb41X0F9XHLHfrlxy45HNFx1MDAwNtb7fFldkiXL+NGGb0O70HjIVyqTo/t+sfJj9r3f/mI+7cfBuZtcdTAwMDJcdTAwMTldg5dreHfb4ZmsPG1cdTAwMDPh/ZXP3y/3es4o7nmf72tH11x1MDAwNbvJ6pXhWbPfusR5dlx1MDAxOO+8P/82f1bDbq38sX6QcUolXHUwMDEzUkgwfzItu9P0P8aWU23Ol/xcdTAwMGauXHUwMDBi9uHSvHpcdTAwMDFcXHpcdTAwMTb/XHUwMDAzkkSmqFx1MDAxN5SCXHUwMDA0QIlcYlx1MDAwYsJcdTAwMTCxXHUwMDFk7kJwXHUwMDA3IVx1MDAwM1hcdTAwMTJKoVx1MDAwMXiEg1DgXHUwMDExJiGmkK5cdTAwMDI8z4V8XdrmwqOFRq3iYaNsd/b6nXK333BcdTAwMDb9vWrPmv7E/Fk5nUHBnuhcdTAwMWJBwPPuSbltt8ae5dZnTbfsul6RXHUwMDFmVXVcdTAwMGJW74d7WVx1MDAwNrZip9lcdTAwMTfadq3mZpNKuW+pW/hQVrN3q+qn1DVavWxcdTAwMWOycnp23e6UW7dcdTAwMGLuL1x1MDAwMnaQONIhXHUwMDA3N5aTh+lcdTAwMWW0zp7az+fx6ZBcdFx1MDAwZvKIXHUwMDBiUTPkuShzhjwsdshcdTAwMGJBXHUwMDFlRYJTwTk1XHUwMDAwXHUwMDBmQlx1MDAxYYo8XHUwMDA0XGLgiFx1MDAwMEpXQN6KlFx1MDAwNzPv9cPSPYf547vKmL3dIWf/NC41ndhcdTAwMTCSXHUwMDE3u5Z9auRyo0z/sX6brWwjNZnvMlx1MDAwZTVx5oVcdTAwMDeGLqr6XHUwMDA0XGKUXCJcYlx1MDAxMMR3XHUwMDAwXHRcdTAwMDGIkFxuXHUwMDFlQLGTXHUwMDExIC5t41x1MDAwM1xiZYJcdTAwMTBIXFxG4/YwU7dnPfWt16GlLvVPf977v//536VIXHR7TphcYimh+cPzkdJcdTAwMDLK8JOS4dZcIrBWejwpZ0a1TqVcdTAwMGZaZNC1XHUwMDBm6UDex+cjl9mh12WfyFx1MDAwMNxcdTAwMTA2WIJ454GFwVxyXHUwMDExRFx0Q8zER5ShMLQxKlx1MDAxMcNcZm/QXHUwMDAx65Toa+dcdTAwMTVnXHUwMDE1fTaUXFw/1nPpy5u4bNRpjlx1MDAxZXOjSefoQjxcdTAwMWSdXVR6XHUwMDE1dNDdRjYy32VcdTAwMWM2XHUwMDEyyOco7ZNg9Fx1MDAwMlxuXHUwMDE5hMeOjcJcdTAwMWQlJFx1MDAxMJCAcVx1MDAxM1x1MDAxZFx1MDAxMVx1MDAxZYpcdTAwMGYogUJcdTAwMTaCYFx1MDAxNXNt3XT0qa+fOsP23n/uge0lo1x1MDAwNXzhJ6PAjUVcdTAwMDDtXHUwMDA0ZPvdYqNSn9S6PVxmnMrlU6VcdTAwMTBcdTAwMDRazS63nU7NhzWEPEjDhjAhMPhFUOxcdTAwMWMj/fZcXEF/rjP6+c5vXHUwMDAxXHUwMDAwMmX0MU6IXHSAXHUwMDE4hUcqINKHuYG7doaqXFy22IW4vTg+uH22XHUwMDBisFx1MDAwMnm2W4jLUNix7t9cdTAwMWOlbtLX9/x5NFx1MDAxONSfLmvxXHUwMDE4KvK8Nny9rlb5ef6QPZT3R0dYXGZcdTAwMGZy28h85tWLxXxe3nPL4oz3uMFcdTAwMGKjZIfGMC+MciRcdTAwMDWURi8sKkpcdTAwMDFcdTAwMDCTjLlcdTAwMTTiltLe3/f+0fl8o/9UVZcy+G5cdTAwMWEkoYHCXHUwMDA1XFxcdTAwMTVJg3/f899mlPVcdTAwMTlpJvtcdTAwMTSFXHUwMDA3hILzXHUwMDE0Rur5Q0gpZj6C3Fx1MDAxNykuIFwis1x1MDAxZLFgnFx1MDAwNKWQVKRJXHUwMDE551i58Vxiclx1MDAwM2BBSlx1MDAxObCQK7tKMMHQXHUwMDBlv8uyKaKAc86MXHUwMDFiboRcdTAwMDScwFx1MDAxOa5cdTAwMDVcdTAwMTecXHUwMDAxsU3Bla5j+9l6/re9uSRM/zH7+z//Yvz2frj46VdA8ObnXHUwMDBikGSr3Fx1MDAxZlx1MDAxYzrttj1QN3qtLzKgY1x1MDAwN+Xe4MDu1OxO3fv8fm5vxzF+p1xuqTrUXHUwMDBisFx1MDAwZlJcdTAwMDAqXHUwMDFmXHUwMDA1ICHVRVLE5namlqByV693XG5Bwels35pcdTAwMDdkxOrU5lx1MDAxN1x1MDAxNbzgtFx1MDAwNn3DKtf8n6rj3J+5zVxiv5aJXGLwuKN8XHUwMDExZp0gXHUwMDFjq1x1MDAwN1x1MDAwNeNI4odOezmtwJKddd6sPuc1ckDObGRvXHUwMDBmvoOa6yO27FxydWGevGabR6hccjlcZni+wJ+RXCKMiVRyM//ykqZFQla2KI/eXHUwMDE47FxcWHftyuuTLN/fXV7fbmDDPPK8v8Buh9mAdsHOXHUwMDEwc5/BTlG3IHpcdTAwMGIqNuzMj2nLYSdcXMv8XHUwMDAxO7o+2LnCc6ZQ3KclXHUwMDBlKMCIuvD4Rditi4+XNpqneGw5o2BcdTAwMTjKXHUwMDFjXHUwMDFi+pqh7TOpXHUwMDE3sILfpPZcXGckvFx1MDAwMlx1MDAwMaM5wphcZt29Uv6pgFxmg1iO01x1MDAwN8D20Vx1MDAwNFxcOlmULuJcdTAwMDfLseVJpZhcdTAwMTPbXHUwMDBlMO6S4+meqcsvT1x1MDAxYWCIXHUwMDE5XHUwMDAwXHUwMDA2XHTwI0zxn9DpZC6nJFx1MDAxOaM7IcLrXHUwMDE3TzO4cnRA73L7XHUwMDA1eHz6yo57OC4xta9cboPJ1Vx1MDAxOFx1MDAxZVx1MDAwZrPpt1eUzedeXHUwMDBipVx1MDAwNFxir1TvdigvTci4p1x1MDAxODVdXHUwMDFmXHUwMDBlO7m3X4vwqCtNxVx1MDAwN0fClCMrXHUwMDEwhrHRaH5IW45GP91R5P/tXHUwMDA06Vx1MDAwZVx1MDAxYqxMV1x1MDAwNO4zP4ZcdTAwMDOClLW7XGZcdTAwMTZ/Qbr7+z86+u+ByJM5XHUwMDFjlCjzLeCNUObzXXIk5Fx1MDAxNvh34Vx0huqZKFx1MDAxN1x1MDAxYon4wDtcdTAwMThlby5AXHUwMDA3XHUwMDFkXHUwMDFlNsdcdTAwMDcvd+SWXGbVc99y4Kkl8O/WXHUwMDEy5M5cdTAwMWVKnFx1MDAwYpGBXHUwMDBigz6eMkNcYqaM4e928sBRsZi9XHUwMDEwvfdiuXHcfbt7IJfnL3G5qeyMnIPK8KrSS2fPT/jTY7mUSYLzhjYqturoofKUyVx1MDAxZHWqd48vtcfCr8V5XHUwMDEw4vCseiSEQJzjOHvWUY9p+8HnzykniK1cdTAwMTN8IDrp4lx1MDAxM3zKweZcdTAwMDK6Y1u/J+7rOv1BaFx1MDAxNtxcdTAwMDY8vlx1MDAwNURcdTAwMTFIbDNcXO7qnMdIIOI+szWBsjMxQ/FRd1C5yljOsXPjXFxcdTAwMWZcdTAwMGWOXHUwMDFk++34NPu8/ajzpMd+lFfJtWHuS2VaP1x1MDAwMcm5clx1MDAxMVx1MDAwMEpcdTAwMGWPK5Jhb3KLx87jSVx1MDAxM1x1MDAxNE9bTDYrp/n05LvJcJTPl09cdTAwMWFHz7dcdTAwMDfZq/akWs0/pItXv1x1MDAxNlx1MDAxOVJcdTAwMTjKhVjo7EZcbuPboeaHtPWgZNhcdTAwMGZKub6dXHUwMDA2dz2lqUzrc6dcdTAwMDFgTDAnrvjNr0uEXjbTS+Sv4+lZ/YHTc1x1MDAxNyqZq4eSZcNoXHUwMDBlWVR7NLtmI/DiaJ6oZFx1MDAwMm2JplxikoJBqlS3O276Ya1cdTAwMDFDoVx1MDAwNUpBXHUwMDAyqaRcdTAwMTIpXHUwMDFilktkyL/zOF27lFx1MDAwMfdjXGJNXHUwMDE5UFx1MDAxZVx1MDAwMVZLaqxXXHUwMDAyLlvNp0BcdTAwMDWT6iFisk2JQElnXGaEyNv0Uy1q81NcdTAwMDRcdTAwMTgvsSSBaKt2b7b773rnM21cdTAwMDCkXHUwMDAwIeoxcaVqsUJcdTAwMTlnXHUwMDAxXHUwMDE58KRcdTAwMDSEXkKkKll0XHRcdTAwMThSQjmBXHUwMDE46axcdTAwMGKIg3KYVPJBXHUwMDFjJz5KK0lcdFNK5JFUeCBcZlx1MDAwMa9SokSkMFx1MDAxMFx1MDAxNFCqXFw44jI4Z1xuStKUpGqxifpcdTAwMDMwyFxyXHUwMDE5Tkrv6cgzI0JQqEszdupqOXVcdTAwMDW5kEqWkDFhXHUwMDFmYlx1MDAxMa6wlC2kN+DiWHy/pMJCXGaldO5cdTAwMTeBglxi9X/uVVhcdTAwMTCmiMRYZ+9hyVxi4mLhXHRD5Xl6woAoJ6lcdTAwMGX9OiBcdTAwMDFF6c6mklxu4Vx1MDAxMFx1MDAwM6pcXFx1MDAwMITw3Fx1MDAwZZ0rs5RcdTAwMDCMXHUwMDExwHROo3rKNJhOteGkKXVcdGGijSBmglx1MDAwM8HjezNnhFx1MDAxNq5cdTAwMGZcdTAwMGXIw/CAZo8qz9dHR6WH7VFcdTAwMTkhm8tU+JxcdTAwMTnlxK0zrlx1MDAwN1xycT1DUJ1BwqaIS8qdWTGOUCy2XHUwMDA2z1x1MDAwZs2nyUtZytd8/6RcXGqzLfTLlSyHJkpoe1x1MDAwYmNcdTAwMWOrrirqrrddlJk3/09p7TVcbvKiXHUwMDFh9U9BXHUwMDE2XGIyXHUwMDAxMPl9bs7qUma9w/kn/cfm49NcdTAwMGJUrqnw2ne1q7OHIKGpXHUwMDEwXHUwMDEwqUeBIUTxU/86qDh65s3O+dXoiVxm0eTo4u02s/WIXHUwMDBi7MgyideIOFx1MDAxYURcdTAwMWNcdGRDMFxilXVcdTAwMDFlYoGwXHUwMDE1maNmtUfg7KpWLmdunEPRXHUwMDE4XHUwMDE1x7nD2JVtt71b+5lcdTAwMWVcdTAwMTZL1mk+c1RqZ67LjV8rUszDU4UgXHUwMDE1XHUwMDAyXHUwMDEwgXl8fJhXc8vxIbDX3+VgnYzkqqyOICSkY4PKadtooJgsIWxfI6Spev/zRklogeo2JVx1MDAwN6krXFydePSedyiygFx1MDAxMFA5LTK+21x1MDAwMlx1MDAwN8W7dPMofdWynlx1MDAwZY/tYXnYLF1vO7I48bstXkcmcbfF2FwiJZh4Llx1MDAxOeNcdTAwMWPyxIy9XHUwMDE1ued8fEybtqhcdTAwMWOc0MbonmdPyPtV7FQgm1x1MDAxY9yfOaVcdTAwMTdr/FguvGbKnbP93kGi3LOMOliJe5TzXHUwMDFlmi5HMFx1MDAxNoyxJdLlzKu57VxiYd5yUu7ZtfymdFx1MDAxZMmBXHUwMDE0Slx1MDAwNDbpXGZtjnum6S/f6FxyLdDkxmydOO7Qz6z4wTMqXj1W+42y3bhcdTAwMDBcdTAwMGbnXbpfXHUwMDBmblx1MDAwMlx1MDAwNHtcckBcdTAwMDCBR1x1MDAxNKlrg/ZTgKjJeNk1I1xy6zXAmZSEXHUwMDAyXHUwMDEyiF/qs6PQmjRcdHXjYLRaQ8QktXrQbtPv/vAgbbW2oy3reVx1MDAxMFx1MDAwMaGB0zViMrTjqOcmXHUwMDAyttz0qiMpKqK2XHQqay3sSVFOXHSjy2S4vT10jnGLZ61BXHUwMDA1XHUwMDE1rs6uT+rD4uX2yHlY+NmfViog8v16kixlSHBwRVx1MDAxNWb93VxilcSd3LZVtU1cdTAwMTe5l6t692pQyp3l705Kk0unwbfRXGKTMtRcdTAwMDbTpUKSXHUwMDEzXHUwMDE5X7rNN73t0i283U5cdTAwMDVZ59ZcbnR1po7KXHUwMDE0g0j5Spjx30NcdTAwMDAgmCl2M+zs2Z23cs8uq6v7r40miC1QwX728F9qJMqiQ1x1MDAwMlxcXHUwMDA2ko3mwTb1KUax+v7/TMtcdTAwMTSn/fODQvXuXHUwMDFjv6fzhdb47OXM2nqsebClj5FkrVx1MDAxZVx1MDAwZo5VXHUwMDFkpLxNXGKQK7Ple1x1MDAwMlx1MDAwMpX8ZY+lr4qw0Vx1MDAxZmT549NcdTAwMTBcdTAwMTROYrdZs586k07m4jl3VK6g4aibr7dO00lcdTAwMDVcdTAwMDQkpFx1MDAwMK5/e5Tz0GJcdTAwMDJcYjGCXHUwMDAyi1htkKOWc9tcdTAwMTFC/bs1kqw1ZoZMfFx1MDAxNNwhhYhChGRyW/3RfCQhYUgsIXDL8JF5h3Su5L+hhmeBNjftkVx1MDAwNq73XHUwMDBizFx1MDAwNHFE57tppVxigPHNwMbTXHUwMDA1LZ9cdTAwMWa1XHUwMDA3zczr3fPTy9FRw9p6J1x1MDAwN0JBfchT+mituVx08bpcdTAwMTOp9Vx1MDAxN4C7XHUwMDFiaHxcdTAwMGY7XZXHMH/brTRQ57B8J+xCxz5cdTAwMWbEZaf+6T56z4yd8lx1MDAwM1x1MDAxZj3XOs7oqDNJtlnn+sPVIJh6OU9EU1x1MDAwNty01UlskJiXc+tBXCK9k1Ogpzl34lx1MDAxMGGm6UdcdTAwMDGIUFxmIaBMbLK8dHNcdTAwMDFrd9PL//iPjbLSXHUwMDAyRVx1MDAxZdWeU13pXHUwMDE3+FxiR3hKgCguYlwiVsvGn5nxgMrz++zxSZpcZp6Kt2+vxfb9eNuhRoG/gI3BtWItXHUwMDFlXHUwMDFkXHUwMDExqbOHXHUwMDEz3Fx1MDAxY1qRjVx1MDAwZeDLVemyUeO3XHUwMDE3XHUwMDE3h/vNm0zOOnbistGTzDt1WL3JXFxfYyuTO76/Q01cdTAwMWWPjVwiz3v0clu7ntxcZlx1MDAxZSRcdTAwMTnlSLr6UD1cdTAwMWW3fzGWwyS0klx1MDAwMFwiQokyXHUwMDA2cXzomVx1MDAxZtO2Q1x1MDAwZvvj3VxmrtVcdTAwMTI0pVtcdTAwMWJ8MImlxJQvXHUwMDE18v51eO6zXHUwMDFmz4Y5blx1MDAwMTmEdVxyXG7jt1x1MDAwZrFcdTAwMWZcdTAwMGbO2OT5XHUwMDFk3Z/mj5xitS+v2dt7cFx1MDAxYjZkXHUwMDFjXHUwMDEwxd6tWFxigoMhITJkNrt2XHUwMDFh/533YoPbPIbiu8/WJFx1MDAxOEHdmstYVVx1MDAxNdHWUPGgcppjOcVcdDHe2fhxcGbfj8ZcdTAwMDWb4PPTXHUwMDFiXFzsX/TiMlx1MDAxMypksq/3LTv34lx1MDAxNJ6bx1Y236BbxkxRd1x1MDAxOUBOMIFBXHUwMDE5JX73XHUwMDFkXHUwMDA2YUN2U4KWyWBghHLd38Q8LSHUUKBcdTAwMThcdTAwMTNE4mVcdTAwMGVvipM+aebI6SyXwrDRuUBcdTAwMGKIw89G05uJQFN02GVBp1x1MDAwMpyCXFxgXGawrp6U3k1Sd/bkvC0pXHUwMDBiOcI152BcdTAwMDc1I0GFl/1CXCKIQOaBJViGpqYgoFveUY7iRKQ2hcFk+1x1MDAxNGDiXHUwMDExNyq8db+ELTxDqMROP6WuS1xikGBifVx1MDAwZaJjLHvullx1MDAwMpAhzpiyV6VywSGBwerdeW+GjU4/iNM4aVFbXHUwMDE0j3pBNJh8OFx1MDAwN5iprminTtyLXHUwMDFjrk4ox1xcMFx1MDAwMMw5iVH2LmerzWj+JZSJ59v7ZCNjUFx1MDAxNrZcdTAwMTfxjEFBXGZcbiRcdTAwMTlFUi3avFB1XHUwMDA2ffh9wH/v9tN2v3rzbj/cVFx1MDAwZlx0bt2Nz0lcdTAwMTD45omD1GdYXHUwMDAwYJrFbigqhC5q26HfvdLh6MdcdTAwMDBxiEUguD790fBqXGaIKVGuXHUwMDAwXFzJoF91Km73spWvXHUwMDE07+BIqpXs9Vx1MDAxYaObXHUwMDA2iOvuXHUwMDE27LOW7D7et8jpoNe5zz11u93XXHUwMDA0XHUwMDAyvM2n91x1MDAxZWneT5x7Wm6mh6XC/XPmJt55XHUwMDAzemStbrR59Vx1MDAwMpA0zFx1MDAxY5T+bVx1MDAwN73hYlx1MDAxYf9OXGaE7CpcdTAwMTD4d4akceAuhpxcdTAwMTBMYSDF6Yfujlx1MDAxNF6Gi1x051x1MDAwNK5cdTAwMTZqWrcznW61XFzJkXv/6FjvVnWofsSV0rl6lcCXZlx1MDAwZc7vy+diL2Arv4vtu8X5XHJGoC96NGn0tEFf00pcdTAwMThkQ9M+3W787rJUXGI4Vlxc6N719PT/XHUwMDBiN4SF+o8yuk2xrWT9auj+OnZ1y/q6Kbx8d6voXHShe273XHUwMDE4IChcdTAwMTV+MGGIXHUwMDAxLJRfXHUwMDFmMJKRSFx1MDAwMcZcdTAwMTjkelx1MDAxMocyaYLSkaxlfMjesm/17lx1MDAxZHwjtXb2nL+e54/u4tCwcMnlh1x1MDAxZZjHf2axbEOdzK5cdTAwMWEvnIApQpyo/0zWb3D/x91cdTAwMDaDccDINlx1MDAwMf6Tf1x1MDAwN73hr1ePN73oXGLQRI8yjGZPZalcdTAwMDJCXGJVZlx1MDAxNkHCN8yeoFx1MDAwMIZAXG5JgFx1MDAwMdA9Xbn+z1R8ttsgWpZdXHUwMDE5ZUBcdTAwMTJ3Xz53hknovlx1MDAxMZdcdTAwMWND9Dum1lxicdMvxOdn+DrZhlHq5WW1+0D78LnSrlJWYYPTXHUwMDEyxiGUXG4kRUJcdTAwMTEqhpRL9afrcuPFncIuXCJ6TOGeN/hFmOSUYUZcdTAwMTBcdTAwMTZYsDjBr4SJ/OFcdTAwMDXuv1x1MDAxY9D+2aSHj1x1MDAwZl+bk+Px+34snURdXHUwMDE1K1x1MDAxZqlEc1x1MDAwN3DuS4uUwJzovuCAXHUwMDE4m8kzlJJKpymAUFx0XHUwMDE5dIVwdirJ/VxiQlVcdTAwMTLlut9cYsUm9jd0XHUwMDAxnzVcItGNXHUwMDAxJVlX99zv10nIXHUwMDFi+mZcdTAwMGJcdTAwMGZcYlx1MDAxNdaP4/1ymqRGXHUwMDBid1x1MDAxZtZcdTAwMTnejs5cdTAwMTaNwj5nPMVcdTAwMDHkUFx1MDAwYlx1MDAxZnXHXaeFxlxmpjBnTJmlXHUwMDE0K1xyXHUwMDE33PKCXHUwMDE0q+PVsYTq3D9cbkz9NyBcYjnLTjG4n09EJFx1MDAwMGFMaXCO0Vx1MDAxNP2hMXGsIEBcdTAwMTWIf696YVx1MDAxZmKeglxiQUpcdTAwMDBkSN2rr6228IpcdTAwMWRAi89cdTAwMTgqztOPXHUwMDAzkrxcdTAwMTnVXHUwMDExZqFEJ4Z6LVx1MDAxNEUtXGZcdTAwMTP13KighMO5XzS3UFxmO/ObbaSNIFx1MDAwZd3exUAwyfhcdTAwMTKtUFx1MDAwZuHFpFxizmnrXHUwMDFldvJcdTAwMTdPt3LYvC5tj4ZcYilfXHUwMDAyXHUwMDAyXHUwMDA0klx1MDAwNF1cdTAwMTHWxGd1YUOSrqGmgkGGXHUwMDEx+/Zcbr+zSa6Mc1xi2dBpPtw99Wuv1zD2POZ1bbmNLl56g0y60Dy06oUqPXWuqlx1MDAxN0nNY1ZIRcxcdTAwMTUlWFNNXHUwMDA1cimEQHhJUFx1MDAwMZWpJOPMk4l6TFtcdTAwMGY9iXzAW+NMZmxKXHUwMDE4MFW1c0EkXHUwMDE1S1xySF+9omJ5cZs/1C9Xtf9p9rfNV7cvIIvI6nb/da9OgFx1MDAxMIf3XFyDQqqHIyiIXHUwMDBmw/rgoVsrlZ/T7JE2L/MjIN9791tcdTAwMGZDXHUwMDE46Mlcblx1MDAwMV1cdTAwMWZcdTAwMTCN7cBccpMkdJ9pwcl3M+B7efJO+bh1e3V8bOVygkv4crNcdTAwMDGmijyvcz5cdTAwMTiObp/eXHUwMDBmT1x1MDAwZi6sa6vb4fmnSlJcZqiMXFzoSsFaV1UhQuFcZkiQ1FeB4vc+Mj+mrYde0PhcdTAwMDR0fcanO85cdTAwMWVZPK/cX2X5b6bR2PLy9jVcbpzTyGbbjS8gXHUwMDA3P+O5L3N1gkOQhVx1MDAxM5yeaSiwXHUwMDAwcVx1MDAwMpk/x1xc9qtcdTAwMTl1w6dAlN9cdTAwMDaFs8pr53Aotlx1MDAxZWWAXHUwMDA1XHUwMDFhKHlwl7ipaSopMzBcdTAwMWNSIINJmporUtxonKPFKmik5V3n1m6fTkpcdTAwMWQr9sSLL+Q/fiPFyU00L1PgXHUwMDBib17GKdGD0GF8ijM/pq1cdTAwMDdcdTAwMWb3Z49KT1elxMHn4rMoP1x1MDAwZulcdTAwMDFPjG3IzVta4L7o5ulcdTAwMTbhW+HnLWBcZmNv83U4eu6iXHUwMDAyf6STM1x1MDAwMsQy3WPeXvO0na4jkLux+EvhXHUwMDFjw9uLxrYjkVx1MDAxMz9cdTAwMGJCSOXacIhILDdcdTAwMGbpUmKM3OVcdTAwMWPf5Oe10vnbYmHYKYLjk0n/xXm/7Vc20OUl8rydtJOv347gdVxy3o1cdTAwMGVykk9qXHUwMDEzKyFcdTAwMTJkknCB1u/ncVx1MDAxY5FIh1x1MDAxOeBgme4x5se09dBcdTAwMGJEWOB872wzLW5cckM9dPJcdTAwMDMhdFP9O4nSwXRcdHFLklx1MDAwMr+jgedcdTAwMDKWiKa+yFx1MDAwZZ5xlE5kXHUwMDEyXHUwMDAy0XN/XHUwMDExXHUwMDA0XHUwMDE0sWlcdTAwMWGXTzY5S+mESS5cdTAwMTmSXHUwMDFjXHUwMDE56vqVYZtChEjEiJ5Jplx1MDAwZVxiXG5cdTAwMWNFyHOWXVx1MDAxYfKyWVxiatH0XHUwMDA0dlNdLqWh5VxiXHUwMDE4ScjoOoqDJIXEVVx1MDAxMfh9aVxihKSQXHUwMDEyP4CQ4FxcQOhNXHUwMDFh0N6+svcoXHUwMDEyXHUwMDAwSkAxX3zCUHGeflx1MDAxY5Dk+Vx0XHUwMDAzLJtYSma09tjz5Fx1MDAxYXBcdTAwMDJcdMdYj+hcdTAwMTaQQVe1xqxcdFx1MDAwMFx1MDAwMVxcKFxyjJkgXGJcYlx1MDAxOOx+lGxcdTAwMDJcdTAwMDRQ66lcdTAwMTCMpX5cYlx1MDAwNGDAg1x1MDAxOZokpWd1fL6EYIFrSjhrK3o/OkphSkZSQImS0Fx1MDAxNUJCYN++JWAyxbm+XVwiuJJcdTAwMTZDby5I1d1cdTAwMTJcdTAwMDZcdTAwMTHjSJE/NzipTH1FibaQTJlFhLKdwlxcNsVcXJdyYFx1MDAxMuzJqz9cdTAwMGLPdFF8p+RPoWKVxK2I6Up6b9ddWvJd+pKilDSKnn4xpUmlVIYgRIQrR3hhh1x1MDAxNMpcIs5G+bKnXHUwMDBiXHUwMDA3xvTq/JDYhOaFzVx1MDAxYpS+T9euXHUwMDFlryuZcd2B3XZ3YtS8MEWwpFx1MDAxY1x1MDAwYqo8WCVApjR0XHUwMDE0slwiS2re6P3y+c+ZXHSCXG6gXHUwMDA3W+tcdTAwMTXkXHUwMDAwkbVcdTAwMTe5RVx1MDAwN4Uj+75cdTAwMDDmLXNTa6d0qy7iXHUwMDEzXHUwMDEy68KroG5cdTAwMDVUXHUwMDExvpRcXIGOqpsztUGkQklcdTAwMTnEUiiTSomv3OnWZY1RpVxcicBcdTAwMDSakuVZeJeYqckkXHRMvIDnXHUwMDBiIdVkrVHiyXbX+lQhnSk5Jlx1MDAxMOqU1sUn8KpQ7DlcdTAwMDNZeHi4+E9P51x1MDAxN/xNaNDooO+eK1x1MDAwMdZoOjKsXHUwMDBijFx1MDAwNOaQSUJWNFWja/r3fNVEYmq96V1vZVx0MJNcdTAwMDFccrl6JFxuXHUwMDAxSn1CpfPXrUGjM0eiO2dhnuKY64GRyldcdTAwMDH+9vzQ1D8gRTlSmldcdTAwMDFcdTAwMTkqo1x1MDAxY1x1MDAwMlOewK6MYOnOWnp7l6JgXHUwMDAwVCvGYFx1MDAwN835pGOl2mjybfqmvVxyxPc78OHSpl/7KNEs/5Vcciq3flBOnWD6XHUwMDBm7dwxXHUwMDFj1Fx1MDAwZiuWPEbnhHiUXCJQdqYuViPahGOu8E7ENSSsk6K35Fx1MDAxN+gkmdL1v1x1MDAxODBlLit73+dAk2AvXHUwMDAzXHUwMDFkc+FUfZ1TobwzXCJNc9vcaVx1MDAxYzut5H5cZuFaSSojQVBmXG4rSteP+r1kKZT2UFxuLU467JJqXHRw92jjb7PkwiVu+rFcdTAwMTa2TWim2Epharlo45phouxcdTAwMTemXHUwMDFlT1ArXHUwMDA05SCWZlpowrkrwrlUvjthQGfsKuuJXHUwMDA3LmLtqim6mXnkXlxi8u1+oKB5xFxmXHUwMDFl5a5t8ZJ6XHUwMDA3M6yseWR0IEW42lx1MDAxMXxabc2S386YVlVugdphXCLk+19XMcuXOEZ3XHUwMDFi9ylcdTAwMWaGhfLuXHUwMDA1R5josu+g8jFcZllIXHUwMDE29ye2cpFf7Fr2qZHLjTL9x/ptNp5JXCKYXHUwMDE398TV/zairVx1MDAxYdx5QUt3XHUwMDE4VVx1MDAxZbXyRYXJ4CDhUXmOXGKF2jP/3Vx1MDAwMt/j9sCNeD2xe6xMW6xgXGYkpkhcdTAwMGaiXHUwMDE2XHUwMDA2dK/o9EDiSIdcdTAwMWPcWE5cdTAwMWWme9A6e2o/n4d7XoBcdTAwMTGkbDLlXHUwMDBmXHUwMDBiXHUwMDFhx/FKWMO0r1xug8nVXHUwMDE4XHUwMDFlXHUwMDBms+m3V5TN515cdTAwMGKlmFx1MDAxYcbb5oWwYJtcdTAwMTdDw1S0a5i6bFx1MDAxZlx1MDAxN0xcdTAwMDTCWJjaNVx1MDAwNJs5zlwi05hcdTAwMDNcdTAwMGVo8v7MtuhcdTAwMTfPt5GrXHUwMDE3w/rUyz6agEsni9JF/GA5tjypXHUwMDE0c2Feg1wibsBcdTAwMDQhOs6tXGaJ+a7tXHUwMDFj2zglXHTlXHUwMDAwKq+MMO3pRCucdXZ8KdW7XHUwMDFkyktcdTAwMTMy7tWOrtP14bCTi1x1MDAxN4/1q1x1MDAwMWaYQWRcbrfuXHUwMDFjjKW7tkCqi1x1MDAwNqnJw+Ch+VJCXHUwMDEwKlx1MDAxOMBratvy/XrAY2agb/YvYmtcYk3+WOexybmmXGJqXGKSwlQo/U/Vo8eIg7U7XHUwMDFj+LZ3az/Tw2LJOs1njkrtzHW5sZpcdTAwMWXgwd6TOz2QRKCBYIKQeZ5cdFx1MDAwYjVcdTAwMDcgwVx1MDAxNENPR66dXHUwMDFlWJ9cdTAwMWXooOLomTc751ejJzJEk6OLt9tMmFx1MDAxZVx1MDAwMIIhpVx1MDAwMSSjVLuFsVpOJoz7l8b4snl1U3hrVcDg8OHw3MrCVlx1MDAxMPfBts1Meid3iqBcdTAwMTNATT3cdlx1MDAxOSqhXZuxXHUwMDA0kiBpzItcdTAwMGW8Od+/kHpiXHUwMDExpdvE87NBt/pd13P5Nbo2f1xcdVx1MDAwNGhscnB/5pRerPFjufCaKXfO9ntcdTAwMDcxydJbL8OxoVxiIcVcdTAwMDXgXHUwMDA0IMFcdTAwMTjDXFxQQ5RcdTAwMWXB3Vx1MDAwNuHydjRhSFx1MDAxMlx1MDAxMJz6rY+KXHUwMDE4S6KVNIVryPXaXHUwMDE2XHUwMDA23Vx1MDAwZlx1MDAxNzn9QjDZXHLC5VlcdTAwMTVcdTAwMGWKd+nmUfqqZT1cdTAwMWRcdTAwMWXbw/KwWbpcdTAwMGUmXqFcdTAwMTTwvtyE6tldhOqBQqLLLDBHWKyxYeGHxiBt+8Qqllxu+2J0VrtcdTAwMWY3m+yuNohHs96UXHUwMDAygYJcdTAwMTlcdTAwMDU7nl2KZ1x1MDAxMeBKXHUwMDBiSGNYzT3s1a9cdTAwMDZcdTAwMTCTXHUwMDE4M7iuMaM7ot1cdTAwMGLCZtItXGZB7cWy7kD9+qxylW/dyphESzy44dLQi9xcdTAwMDCb3ZjNJVlVQC5cdTAwMDTA5p7C4Vx1MDAxNdJcYlx1MDAxMIrWNmVzXHUwMDFiKNXDoIlO2fye3uCWrFrj0sX9oSztn1WuXyb3znO82lx1MDAwN+XlerAogWE6SVx1MDAxMIu7kbdLY1Fwhlx1MDAxMFx0OovTRVx1MDAwZsVcIlx1MDAwNEjq4uht8iDXt2OU7MTb78Gi/dSZdDJcdTAwMTfPuaNyXHUwMDA1XHJH3Xy9dZpeXHKLYi6hUZu3u7lAK6SjMoApNHmbXHUwMDEwh3ftwXquXHUwMDFixGsoc4dbUVjk3b7dyFx1MDAxOKCeOO2fXHUwMDFmXHUwMDE0qnfn+D2dL7TGZy9n7nYznqRP5fxiJpV/wCFcIq7chr0tXHUwMDE4P21dOPvNqzNayjSv65XO2GHDM8O8MMOQPe6tlpEgXGL73ZC9pdxIXHUwMDA2JNOzXHUwMDEwTPhcdTAwMGWGmGZzvyhUWiFeXHUwMDBm9E07kb/LXHUwMDExe527trBE44JWut2MLc6dw/bBWSzI+KdZ7SDzVchcYj1hhbhcdTAwMTcy3iBaQNTDkFKuKfKyUo/e3zdoXCL7s0Xbl9iDXHUwMDFhXGKRaVx1MDAxNKWyjiRV0lx1MDAwMIWySVx1MDAwMFx1MDAxM6bhIbtcco4lTU5cdTAwMDQ4kIBcdTAwMDBjolx1MDAxMFxmou5cdTAwMTNfXGYxXWeTPLqW7sS3XHUwMDFli3M/Qt70XHUwMDBif/PuxjItkVx1MDAwMFx1MDAxNEKZqFx1MDAxNEMoiNKZsSqjXHUwMDEytkJPSXZ8lreHpUH9/Vx1MDAwMlx1MDAxN9uVq2pzXHUwMDFji1JdzmZgMMqOU1fjVI1ehXpTzFx1MDAwN4VmXHJcdTAwMTBCgW58saYtzVx1MDAxZKP6MVx1MDAxM918J1x1MDAwMjOS+muKRZBQdzuAS2GG4mmrJ2nsX1x1MDAxMFx1MDAxZSdV3p6kXHUwMDEy4FV8t5DuvV9cdTAwMWUoXHUwMDE24Ks1XHUwMDAw8tffXFz8w89cdTAwMTX6Ue52XHUwMDBiXHUwMDAztT4zNv7xZlujg6C0//F5+tLHT1x1MDAwMa0l3ZraY7/94bf/XHUwMDA3y588PSJ9
  
    
   
  Chain snapshots created pre_sequence() ⚡ sequence_num = 0 sequence_num <  sequences_count flow_num = 0 flow_num < flows_count post_sequence() ⚡ Chain snapshots restored pre_flow(flow) ⚡ flow() post_flow(flow) ⚡ false Run invariants? pre_invariants() ⚡ sequence_num++ flow_num++ Done All invariants  executed? true pre_invariant(invariant) ⚡ invariant() post_invariant(invariant) ⚡ post_invariants() ⚡ false false true true true false  
 
Example 
Putting all of the above together, here is an example of a FuzzTest that tests the Counter contract:
from  woke.testing  import  * 
from  woke.testing.fuzzing  import  * 
from  pytypes.contracts.Counter  import  Counter 
class  CounterTest ( FuzzTest ): 
counter :  Counter 
count :  int 
def  pre_sequence ( self )  ->  None : 
self . counter  =  Counter . deploy () 
self . count  =  0 
@flow () 
def  flow_increment ( self )  ->  None : 
self . counter . increment () 
self . count  +=  1 
@flow () 
def  flow_decrement ( self )  ->  None : 
with  may_revert ( Panic ( PanicCodeEnum . UNDERFLOW_OVERFLOW ))  as  e : 
self . counter . decrement () 
if  e . value  is  None : 
self . count  -=  1 
else : 
assert  self . count  ==  0 
@invariant ( period = 10 ) 
def  invariant_count ( self )  ->  None : 
assert  self . counter . count ()  ==  self . count 
@default_chain . connect () 
def  test_counter (): 
default_chain . default_tx_account  =  default_chain . accounts [ 0 ] 
CounterTest () . run ( sequences_count = 30 ,  flows_count = 100 ) 
The test performs 30 test sequences, each consisting of 100 flows. It tests with two flows of the same probability: flow_increment and flow_decrement.
The invariant invariant_count is executed after every 10 flows.
Generating random data 
There are two ways to generate random data in Woke fuzz tests.
Flow arguments 
Every flow function can accept additional arguments to the implicit self. These arguments are generated based on the type hints:
@flow () 
def  flow_set_count ( self ,  count :  uint )  ->  None : 
self . counter . set_count ( count ,  from_ = self . counter . owner ()) 
self . count  =  count 
Flow argument types can be any of the following:
integer types ranging from uint8 to uint256 and from int8 to int256, including uint and int, 
byte types ranging from bytes1 to bytes32, including bytes and bytearray, 
List, including List1 to List32 helper annotations (e.g. List16[uint8]),bool,str,Address, does never generate the zero address,any Enum, including enums generated in pytypes, 
any dataclass, including dataclasses generated in pytypes. 
 
All flow arguments are generated non-biased, i.e. the probability of generating a value of a given type is the same for all values of that type.
For types that have length, the length is generated in the range 0 to 64.
For generating fine-tuned random data, it is recommended to use the random functions from the woke.testing.fuzzing module.
Random functions 
Woke testing framework provides a set of random functions that can be used to generate random data.
random_account() 
random_account() returns a random account from a given chain. It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
lower_boundlower bound index of chain.accounts to choose from 
0 
upper_boundupper bound index of chain.accounts to choose from 
None (i.e. len(chain.accounts)) 
predicatepredicate that the account must satisfy 
None (i.e. no predicate) 
chainchain to choose the account from 
default_chain 
 
random_address() 
random_address() returns a random address. It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
zero_address_probprobability of generating the zero address 
0 
 
random_int(min, max) 
random_int(min, max) returns a random integer in the range min to max. It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
min_probprobability of generating min 
None (i.e. 1 / (max - min + 1)) 
max_probprobability of generating max 
None (i.e. 1 / (max - min + 1)) 
zero_probprobability of generating 0, if min < 0 < max 
None (i.e. 1 / (max - min + 1)) 
edge_values_probvalue to use for min_prob, max_prob andzero_prob if not set 
None 
 
random_bool() 
random_bool() returns a random boolean value. It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
true_probprobability of generating True 
0.5 
 
random_string(min, max) 
random_string(min, max) returns a random string of length in the range min to max. It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
alphabetalphabet to choose characters from 
string.printable 
predicatepredicate that the string must satisfy 
None (i.e. no predicate) 
 
random_bytes(min, max) 
random_bytes(min, max) returns a random byte array of length in the range min to max. If max is not specified, it generates exactly min bytes.
It accepts the following keyword arguments:
Argument 
Description 
Default value 
 
 
predicatepredicate that the byte array must satisfy 
None (i.e. no predicate) 
 
Launching tests in parallel 
Woke testing framework allows running the same test in parallel with different random seeds.
Multiprocess tests are launched using the woke fuzz command:
  fuzz  tests/test_counter_fuzz.py  -n  5 
Info
The command woke fuzz does not utilize the pytest framework to collect and execute tests.
As a consequence, the pytest features like fixtures  are not available. Test functions must start with the test prefix.
Test classes are not supported.
 
If a test process encounters an error, the user is prompted whether to debug the test or continue fuzzing.
While debugging, other processes are still running in the background.
By default, nothing but status of each test is printed to the console. Using the --passive flag, the output of the first process is printed to the console.
Standard output and standard error of all processes are redirected to the .woke-logs/fuzz directory.
Reproducing a failed test
For every process, Woke generates a random seed that is used to initialize the random number generator.
The seed is printed to the console and can be used to reproduce the test failure:
  fuzz  tests/test_counter_fuzz.py  -n  5   -s  62061e838798ad0f
A random seed can be specified using the -s flag. Multiple -s flags are allowed.