Thursday Mornings With Python, Part 2

Thursday Mornings With Python, Part 2

It's that time of the week again... yay! This honestly feels like Christmas to me.

I prefer real coding even more but I LOVE courses.

My course-taking days might come to an end soon.

But for now I am very grateful to be being given the opportunity to upskill a lot more.

THANKS! ❤️

A holographic image summarising what I learned this morning.

Introduction to Testing

Moving on from the fact that I have been doing lots of testing for 6 months, here's some of the interesting theory behind it. Why test? Things can go wrong with our code:
  • syntax errors and exceptions
  • MISTAKES IN PROGRAM LOGIC
    • ("WHAT ME? NEVER!" - THE PRINCESS ANASTASIA IN ANASTASIA)
    • THIS CAN CAUSE THE PROGRAM TO BEHAVE IN UNEXPECTED WAYS.
And furthermore: 
  • Testing is crucial to creating quality software
  • The goal of testing isn't just to find bugs
    • It's to find them quickly
  • LEAVING BUGS UNFOUND AND UNRESOLVED CAN LEAD TO MASSIVE CONSEQUENCES IN THE REAL WORLD.
  • !!!!
!!!

Two Categories of Testing

  • Manual Testing
    • A physical person interacts with the software much as the user would
    • It also just involves running the code manually and testing it out, omg
  • and Automated Testing
    • Testing with code
According to the course, these are the main too.

The Assert Statement

I have done MANY MANY DOZENS OF THESE. Excited to see if I learn something new.

The assert statement "provides as an easy way to perform simple tests in our code."

The general syntax looks like:

assert <condition>, 'Message if condition is not met'

This is interesting - it helps me to understand the output of my tests better. I only write the <condition> bit, but reading this really helps me to break down my error messages.

"An assert statement is a quick and powerful way to verify that a program is in the correct state."

"They can be used to catch mistakes early and make sure we avoid any catastrophes."

TIL that you can write your own assertion error messages!!!

The lesson example is on an airport - so I have written this assertion and message:

assert destination in destinations, 'Sorry, Small World currently does not fly to this destination!'

It was fun writing my own error message.

I wonder if I'll ever need to do that for real too.

Unit Testing

Assertion statements don't tell us WHAT we should test. This is something I am trying to get better at. What do we test? And why? Might be good for a chat later on but let's see.

"Generally, we can start by testing the smallest unit of a program"

I could talk unit, integration and e2e testing and costs and benefits for ages.

The course uses the example of testing a door - different units of a door could be the handle, the lock, the doorbell... 

IT'S THE SAME WITH OUR CODE.

Why should it be any different??!

A single unit might test... "A FUNCTION, A LOOP OR A VARIABLE." I repeat: 

A single unit might test:
  • A function
  • A loop
  • A variable
Super easy to get this... super easy to forget this in the heat of a moment of writing code. So yes let's see...

"A  unit test validates a single behaviour and will make sure all of the units of a program are functioning properly." Well yes, that's all very well but... that's fair but you can also test too much surely right and waste developer time

Probably just best to test the main purpose and the main output of the function? "A TEST CASE VALIDATES THAT A SPECIFIC SET OF INPUTS PRODUCES AN EXPECTED OUTPUT FOR THE UNIT WE ARE TRYING TO TEST." Sorry, struggling to take in new information.

A test case validates that a specific set of inputs produces an expected output for the unit we are trying to test. I'm interested in the second part of the sentence.

"That a specific set of inputs produces an expected output for the unit we are trying to test." A specific set of inputs

-> produces an expected output

-> FOR the UNIT we are trying to test. 

Got it so we are just trying to see if our toaster works.

Given white bread, does our toaster produce toast? Does our defrost function work? Can we stop the toasting process in the middle if we need it to?

A single function might be a single unit. We might need to create several "test cases". 

Again I think that we can over-test and so we need to be careful here I think please thanks.

but the course recommends edge cases too...

HOW DO I DECIDE? HOW DO I KNOW? WHEN TO DO EDGE CASES AND WHEN NOT TO? I remember a big project in my old job where a test uncovered a huge risk for errors...
But it was an edge case.

So what if we hadn't of done it??!? The course seems to recommend "having several test cases for a wide variety of inputs." It says: "We can create as many test cases as we see fit for a single unit, and we should try to test all the unique types of inputs our unit will work with."

Curious if my colleague agrees here - thanks.

Btw I am writing loads of code here as part of the lesson but not sticking the examples in here, please - thanks.

Or fine: 
def get_nearest_exit(row_number):
  if row_number < 15:
    location = 'front'
  elif row_number < 30:
    location = 'middle'
  else:
    location = 'back'
  return location

# Write your code below:

def test_row_1():
  assert get_nearest_exit(1) == "front", "The nearest exit to row 1 is in the front!"

def test_row_20():
  assert get_nearest_exit(20) == "middle", "The nearest exit to row 20 is in the middle!"

  def test_row_40():
    assert get_nearest_exist(40) == "back", "the nearest exit to row 40 is in the back!"

  test_row_1()

  test_row_20()

  test_row_40()

There you go this what I did for that tiny unit (no pun intended). Also had to fix some errors that were built into the first part of it. By the course. Thanks.

Python's unittest Framework

I think that this is what we use to run pytest? definitely one to chat about here

In the previous lesson:
  • Writing a new function each time was annoying and arduous
  • We didn't have a way of grouping tests
  • If one test failed none would run
Luckily we have unittest to help with this...

unittest  provides us with a test runner...

A component -> "which collects and executes tests and then provides results to the user." It also allows us to
  • group
  • setup
  • teardown
  • skip
  • and much much more
our tests.

Just wanna confirm if this is what we use at work or if this is just a good framework anyway that the course is using for teaching purposes and to teach us... thanks.

(I don't think we use it but I am learning from it anyway so thanks).

Okay this is not what we use but it's super interesting to learn it anyway.

It definitely gives me a deeper understanding of how and why it is that we are doing what we are doing.

Learning different syntaxes for similar things will do that for me - thank you.
import unittest

def get_nearest_exit(row_number):
  if row_number < 15:
    location = 'front'
  elif row_number < 30:
    location = 'middle'
  else:
    location = 'back'
  return location

class NearestExitTests(unittest.TestCase):
  def test_row_1(self):
    self.assertEqual(get_nearest_exit(1), 'front', 'The nearest exit to row 1 is in the front!')

  def test_row_20(self):
    self.assertEqual(get_nearest_exit(20), 'middle', 'The nearest exit to row 20 is in the middle!')

  def test_row_40(self):
    self.assertEqual(get_nearest_exit(40),'back', 'The nearest exit to row 40 is in the back!')

unittest.main()

Assert Methods I: Equality and Membership

Only have time to take two minutes to look at this... sadly.

The unittest framework relies on "built-in assert methods instead of assert statements to track results without actually raising any exceptions."

Okay not too relevant for me to learn 

"Specific assert methods take arguments instead of a condition, and like assert statements, they can take an optional message arguments."

As well as having assertEqual you can have assertIn - this to me is like having == and in in my regular tests.

They also have assertTrue - think it would be == True or is True 

A few quick notes on this please: I recovered an old post from my other blog (which I paused when it became evident that I needed to dramatically upskill in Python) on identity vs. equality. 

Turns out I was talking about a slightly different topic but what came up for me is:
  • You would use == for numbers and strings
  • You would use is and is not for None
    • You would probably use is and is not for True and False i.e. bools but these ones are a bit more flexible
  • We talked about using in or not in - you couldn't use this on None - because there has to be something IN the thing for you to check if there is something in or not in it lol
Thanks.

Really simple so far - there's just a lot of text - sorry.

Conclusions

Discussions - A couple of sprinkles of gold dust from my senior

Knowing what to test for and what not to test for - how many niche or edge cases to test for - comes with experience.

What is the function intention? Why am I writing this function? What is its intention? What is its job? 

We test to see if it's doing that job.

If your code has any error handling, WE CAN TEST TO SEE IF IT THROWS THOSE ERRORS WHERE APPROPRIATE.

What's the thing's job? What would I expect it to do?

ARE THERE DIFFERENT FAILURE SCENARIOS? THEN TEST FOR THOSE

TEST FOR THOSE - TEST FOR THOSE - TEST FOR THOSE PLEASE - THANKS.

Experience comes with time

Testing is an art form.

TESTING IS AN ART FORM!!!

Vibes ✨

Adaptibility.

You pick up the "vibes" of the code.

From the codebase, you can tell✨

From the codebase, you can tell. What's the vibe?

What's the style? ✨

What's the style?

"The Imitation Game" came on again

The main theme. 

Comments

Popular posts from this blog

Hello World

Yosemite

Two Lines of Thought, Makes Me Wonder What I'm Missing