how to measure sleep duration: test_duration_w_hours_and_minutes¶
This is part 2 of a program that calculates the difference between a given wake and sleep time.
I want to test the duration function with timestamps where both hours and minutes are random.
RED: make it fail¶
I change the name of
test_duration_w_hoursdef test_duration_w_hours_and_minutes(self): sleep_time = random_timestamp() wake_time = random_timestamp()
then add a variable for the difference between the hours
difference_hours = ( int(wake_time.split(':')[0]) - int(sleep_time.split(':')[0]) ) self.assertEqual( src.sleep_duration.duration( wake_time=wake_time, sleep_time=sleep_time ), difference_hours )
and change the expectation to a timestamp format
self.assertEqual( src.sleep_duration.duration( wake_time=wake_time, sleep_time=sleep_time ), f'{difference_hours:02}:00' )
the terminal shows AssertionError
AssertionError: -3 != '-3:00' AssertionError: 0 != '00:00' AssertionError: 8 != '08:00' AssertionError: 16 != '16:00'
the
durationfunction returns a number and the test expects a string. I change it to match the expectationdef duration(wake_time=None, sleep_time=None): difference_hours = ( get_hour(wake_time) - get_hour(sleep_time) ) return f'{difference_hours:02}:00'
then make a copy of
difference_hoursin the test, change the name, and change0to1on each line to get the difference between the minutes ofwake_timeandsleep_timedef test_duration_w_hours_and_minutes(self): sleep_time = random_timestamp() wake_time = random_timestamp() difference_hours = ( int(wake_time.split(':')[0]) - int(sleep_time.split(':')[0]) ) difference_minutes = ( int(wake_time.split(':')[1]) - int(sleep_time.split(':')[1]) )
I also add
difference_minutesto the expectationself.assertEqual( src.sleep_duration.duration( wake_time=wake_time, sleep_time=sleep_time ), ( f'{difference_hours:02}:' f'{difference_minutes:02}' ) )
and change the
random_timestampfunction to have random numbers from0up to and including59for the minutesdef random_timestamp(): return ( f'{random.randint(0,23):02}:' f'{random.randint(0,59):02}' )
I get random success when
random_timestampreturns00for the minutes and AssertionError when it does notAssertionError: '-18:00' != '-18:44' AssertionError: '05:00' != '05:-16' AssertionError: '-2:00' != '-2:-26' AssertionError: '16:00' != '16:-25'
the
durationfunction returns00for the minutes part of the duration, and the test expects the difference between the minutes ofwake_timeandsleep_time
GREEN: make it pass¶
I make a copy of
difference_hoursinduration, change the name, then add it to the return statementdef duration(wake_time=None, sleep_time=None): difference_hours = ( get_hour(wake_time) - get_hour(sleep_time) ) difference_minutes = ( get_hour(wake_time) - get_hour(sleep_time) ) return ( f'{difference_hours:02}:' f'{difference_minutes:02}' )
the terminal shows AssertionError
AssertionError: '20:20' != '20:-6' AssertionError: '06:06' != '06:17' AssertionError: '-16:-16' != '-16:-7' AssertionError: '02:02' != '02:07'
the function returns the same numbers for hours and minutes because
difference_hoursanddifference_minutesare the same. I make a copy of theget_hourfunction, call itget_minutesand change the index to get the second item from the timestamp splitdef get_minutes(timestamp): return int(timestamp.split(':')[1])
then change the calls in
difference_minutesdifference_minutes = ( get_minutes(wake_time) - get_minutes(sleep_time) )
the test passes! There is something wrong with this calculation…
REFACTOR: make it better¶
test_duration_calculation¶
The duration function returns a subtraction of hours and a subtraction of minutes which does not give the right difference between the timestamps
RED: make it fail¶
If duration is given a wake_time of '03:30' and a sleep_time of '02:59', it should return '00:31' as the difference between the timestamps
def test_duration_calculation(self):
self.assertEqual(
src.sleep_duration.duration(
wake_time='03:30',
sleep_time='02:59'
),
'00:31'
)
def test_duration_w_hours_and_minutes(self):
...
the terminal shows AssertionError when I add test_duration_calculation
AssertionError: '01:-29' != '00:31'
duration returns '01:-29' which is not a real duration, the calculation has to change
GREEN: make it pass¶
I add a return statement to the
durationfunction where I multiplydifference_hoursby60then add it todifference_minutesto get the total difference in minutesreturn ( difference_hours*60 + difference_minutes ) return ( f'{difference_hours:02}:' f'{difference_minutes:02}' )
the terminal shows AssertionError for
test_duration_w_hours_and_minutesAssertionError: -458 != '-7:-38' AssertionError: -936 != '-15:-36' AssertionError: -31 != '-1:29' AssertionError: 213 != '03:33'
durationreturns the difference as a number and the test still expects a string. I add the unittest.skip decorator to skip it@unittest.skip def test_duration_w_hours_and_minutes(self): ...
the terminal shows AssertionError for
test_duration_calculationAssertionError: 31 != '00:31'
the function returns the right number of minutes for the difference. I need a way to change it to hours and minutes to match the expectations of the tests. I add the unittest.skip decorator to skip it while I test the solution
@unittest.skip def test_duration_calculation(self): ...
If I divide the total number of minutes by
60, the whole number from the result is the hours and the remainder is the minutes
test_floor_aka_integer_division¶
The // operator returns a whole number which is how many times the bottom number can be multiplied to get a whole number that is equal to or as close to the top number as possible. It should give me the hours when I divide by 60
I add a failing test for it
def test_floor_aka_integer_division(self): self.assertEqual(120//60, 0) @unittest.skip def test_duration_calculation(self): ...
the terminal shows AssertionError
AssertionError: 2 != 0
the result of
120divided by60is2with a remainder of0. I change the expectation to the right value.self.assertEqual(120//60, 2)
and it passes
I add another assertion
self.assertEqual(150//60, 0)
the terminal shows AssertionError
AssertionError: 2 != 0
the result of
150divided by60is also2but with a remainder of30. I change the expectation to the right valueself.assertEqual(150//60, 2)
the test passes
test_the_modulo_operation¶
The % operator returns the remainder when a number is divided by another, it should give me the minutes when I divide by 60
I add a failing test for it
def test_the_modulo_operation(self): self.assertEqual(120%60, 2) @unittest.skip def test_duration_calculation(self): ...
the terminal shows AssertionError
AssertionError: 0 != 2
the remainder when
120is divided by60is0. I change the expectation to the right valueself.assertEqual(120%60, 0)
the test passes
I add another assertion
self.assertEqual(150%60, 0)
the terminal shows AssertionError
AssertionError: 30 != 0
the remainder when
150is divided by60is30. I change the expected value in the test to the right valueself.assertEqual(150%60, 30)
the terminal shows green again
I comment out the unittest.skip decorator for
test_duration_calculationto get back the AssertionError# @unittest.skip def test_duration_calculation(self):
and change the first return statement in the
durationfunction to a variable for the total difference in minutesdifference = ( difference_hours*60 + difference_minutes ) return ( f'{difference_hours:02}:' f'{difference_minutes:02}' )
then add a variable for the hours of the duration using floor (integer) division
difference = ( difference_hours*60 + difference_minutes ) duration_hours = difference // 60
and a variable for the minutes of the duration using the modulo operator
duration_hours = difference // 60 duration_minutes = difference % 60
then change
difference_hoursanddifference_minutesin the return statementreturn ( f'{duration_hours:02}:' f'{duration_minutes:02}' )
the test passes
I remove the unittest.skip decorator from
test_duration_calculationand comment it out for
test_duration_w_hours_and_minutes# @unittest.skip def test_duration_w_hours_and_minutes(self): ...
the terminal shows random successes and random AssertionError
AssertionError: '-11:46' != '-10:-14' AssertionError: '-6:04' != '-5:-56' AssertionError: '10:50' != '11:-10' AssertionError: '16:50' != '17:-10'
the calculation in the test is still not right. I change it to match the
durationfunctiondifference = ( difference_hours*60 + difference_minutes ) duration_hours = difference // 60 duration_minutes = difference % 60
then change the variables in the expectation
self.assertEqual( src.sleep_duration.duration( wake_time=wake_time, sleep_time=sleep_time ), ( f'{duration_hours:02}:' f'{duration_minutes:02}' ) )
the test passes with no more random failures
I take out the unittest.skip decorator from
test_duration_w_hours_and_minutesand remove
test_duration_calculationbecause it is covered bytest_duration_w_hours_and_minuteswhich has the right calculationthen add a function in
sleep_duration.pyto changeget_hourandget_minutesdef read_timestamp(timestamp=None, index=0): return int(timestamp.split(':')[index]) def duration(wake_time=None, sleep_time=None): ...
call it in
durationdef duration(wake_time=None, sleep_time=None): difference_hours = ( read_timestamp(wake_time) - read_timestamp(sleep_time) ) difference_minutes = ( read_timestamp(wake_time, 1) - read_timestamp(sleep_time, 1) ) ...
and remove
get_hourandget_minutes. The terminal shows all tests are still passing!
review¶
The challenge is to write a program that calculates the difference between a given wake and sleep time. I ran the following tests to get something that comes close to doing it
test_duration_w_hours_and_minutes where I
used random.randint to generate random numbers
from the
24hours in a dayand the
60minutes in an hour
then how to pass values them in the timestamp strings that are given to the function
and test_duration_calculation to make sure that the
durationfunction returns the right difference betweenwake_timeandsleep_timeand changes it to a timestamp format
by using floor (integer) division to get the hours
and the modulo operation to get the minutes
Would you like to test duration with an earlier wake than sleep time?