[Tutor] Testing functions

ThreeBlindQuarks threesomequarks at proton.me
Mon Jun 26 20:34:54 EDT 2023


Matt gave a somewhat more advanced reply as to how to test the function you want which might look a bit more like this:

So here is a variation of your code where there is a function called "categorize" that does not print anything but just returns a default string or a specific one:

def categorize(number):
  value = "The number is " + str(number)
  
  if number <= 5:
    value = "The number is 5 or smaller."
  elif number == 33:
    value = "The number is 33."
  elif number < 32 and number >= 6:
    value = "The number is less than 32 and greater than 6."
  return value

You can test it by hand at the prompt:

>>> categorize(1)
'The number is 5 or smaller.'
>>> categorize(666)
'The number is 666'
>>> categorize(32.5)
'The number is 32.5'

Or you can use a loop to test say from -2 to 35-1 as in:

for numberness in range(-2,35):
  print(numberness, ": ", categorize(numberness))
  
  
You get something like this:

-2 :  The number is 5 or smaller.
-1 :  The number is 5 or smaller.
0 :  The number is 5 or smaller.
1 :  The number is 5 or smaller.
2 :  The number is 5 or smaller.
3 :  The number is 5 or smaller.
4 :  The number is 5 or smaller.
5 :  The number is 5 or smaller.
6 :  The number is less than 32 and greater than 6.
7 :  The number is less than 32 and greater than 6.
8 :  The number is less than 32 and greater than 6.
9 :  The number is less than 32 and greater than 6.
10 :  The number is less than 32 and greater than 6.
11 :  The number is less than 32 and greater than 6.
12 :  The number is less than 32 and greater than 6.
13 :  The number is less than 32 and greater than 6.
14 :  The number is less than 32 and greater than 6.
15 :  The number is less than 32 and greater than 6.
16 :  The number is less than 32 and greater than 6.
17 :  The number is less than 32 and greater than 6.
18 :  The number is less than 32 and greater than 6.
19 :  The number is less than 32 and greater than 6.
20 :  The number is less than 32 and greater than 6.
21 :  The number is less than 32 and greater than 6.
22 :  The number is less than 32 and greater than 6.
23 :  The number is less than 32 and greater than 6.
24 :  The number is less than 32 and greater than 6.
25 :  The number is less than 32 and greater than 6.
26 :  The number is less than 32 and greater than 6.
27 :  The number is less than 32 and greater than 6.
28 :  The number is less than 32 and greater than 6.
29 :  The number is less than 32 and greater than 6.
30 :  The number is less than 32 and greater than 6.
31 :  The number is less than 32 and greater than 6.
32 :  The number is 32
33 :  The number is 33.
34 :  The number is 34

Now obviously you would need to inspect the above by hand to see if it makes sense. And there are many ways to test selected ranges.

And you might supplement it with explorations like this:

>>> categorize()
TypeError: categorize() missing 1 required positional argument: 'number'
>>> categorize(5, 32)
TypeError: categorize() takes 1 positional argument but 2 were given
>>> categorize("42")
TypeError: '<=' not supported between instances of 'str' and 'int'
>>> categorize(complex(3, 5))
TypeError: '<=' not supported between instances of 'complex' and 'int'

Obviously some of these tests might be deemed irrelevant but they might actually make you reconsider and rewrite things. Of course if the requirements for the project are only what is described, you can stop here,

As an example, you could have the code not FAIL when given cases like the above. You could define the function to take anything from no arguments to a lot of arguments and then check what you got and do something appropriate. For no arguments, the return would be that the category is NOTHING. For multiple, maybe you return a list of individual categories. 

Maybe if you got a string as an argument, you might try to convert it to an "int" and if it works, categorize it. If it is imaginary, maybe test the real part. Floating point numbers maybe can be rounded or truncated. You get the idea.

Note again my example function is not quite the same as your code and is designed to return a string rather than print it. And for more significant testing, as several have mentioned, there are MANY options that help automate it.

And as I noted earlier, your code does not seem quite correct to me.

-Q



Sent with Proton Mail secure email.

------- Original Message -------
On Monday, June 26th, 2023 at 4:17 PM, Mats Wichmann <mats at wichmann.us> wrote:


> On 6/26/23 04:16, Jack Simpson wrote:
> 
> > Hi.
> > I have just been playing around with functions and wanted to know where
> > should i be in putting variables to test out a function block i have
> > written?
> > 
> > This one is just an example for demonstration but where should I be
> > defining the value of username here to test the function?
> > 
> > > > > def hint_username(username):
> > > > > ... if len(username) < 3:
> > > > > ... print("Invalid username, must be at least 3 characters long")
> > > > > ... else:
> > > > > .. . print("Valid username")
> 
> 
> Here's one possibility:
> 
> You can write test functions that hold the various combinations you want
> to try. If you use an existing test framework this is pretty simple.
> You can prepare a test function that has the same name but a "test_"
> prefix, and write the tests to validate your usage there. The great
> thing about writing tests this way - "together with your code" - is you
> often think of cases that you didn't think of originally when writing
> your function - there's even a line of thinking that you should write
> your tests first, then write the code so the tests pass. Anyway - what
> if someone misunderstands and passes an integer to your function. What
> should it do?
> 
> So here's a really trivial example using a variant of your code
> (notice the "print" calls have been replaced with a return - it's more
> common to have a function "do something" rather than print stuff - the
> latter is kind of typical when you're just starting out but becomes less
> prominent later). The test framework handles running the tests for you.
> 
> def hint_username(username):
> if len(username) < 3:
> return "Invalid username, must be at least 3 characters long"
> else:
> return "Valid username"
> 
> def test_hint_username():
> # are short names detected?
> assert hint_username("gb") == "Invalid username, must be at least
> 3 characters long"
> # are long names accepted?
> assert hint_username("georgebrown") == "Valid username"
> # are bogus usernames rejected?
> # assert hint_username(123) == ?? what should function return here?
> 
> 
> PyTest will perform "test discovery" - files whose names start with
> test_ if you give it no filenames to search, and locate what look like
> test functions in those, or if you give it filenames, it will look for
> test functions in those (starting wtih test_), and run them for you.
> Like:
> 
> $ pytest username.py
> ============================= test session starts
> ==============================
> platform linux -- Python 3.11.3, pytest-7.3.2, pluggy-1.2.0
> rootdir: /home/user/work
> plugins: typeguard-4.0.0
> collected 1 item
> 
> username.py .
> [100%]
> 
> ============================== 1 passed in 0.00s
> ===============================
> $
> 
> 
> _______________________________________________
> Tutor maillist - Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


More information about the Tutor mailing list