5
\$\begingroup\$

I try to use unittest for conference class, but I am not sure that I have considered all condition or more complex tests should be added?

conference.py

from datetime import timedelta, datetime


class Conference:

    def __init__(self):
        self.inputs ='input.txt'
        self.outputs = 'output.txt'
        self.talks = self.proposals_extract()
        self.Track = 1
        
    def proposals_extract(self):
        talks = {}
        f = open(self.inputs)
        try:
            while True:
                line = f.readline()
                duration = ''.join(filter(lambda i: i.isdigit(), line))
                if duration:
                    talks[line] = duration
                elif (not duration) and  line:
                    print('for proposal {} no duration has been detected'.format(line))
                    break
                if not line:
                    break         
        except FileNotFoundError as e:
                raise
        f.close()
        return talks
    
    def delete_content(self, pfile):
        pfile.seek(0)
        pfile.truncate()
        
    def format_time(self, hours):
         return (datetime.min + hours).strftime('%I:%M %p')
    
    def plan(self, start, end, Output):
        start = timedelta(hours=start)
        end = timedelta(hours=end)
        
        while start < end and self.talks:
            item = self.talks.popitem()
            duration = item[1]
            proposal = item[0]
            print(self.format_time(start), ' ', proposal)
            Output.write('{}  {} '.format(self.format_time(start), proposal))
            start += timedelta(minutes=int(duration))
        start = self.format_time(hours=start) 
        return start
                
    def print_plan(self):
        O = open('output.txt', 'a')
        self.delete_content(O)
        lunch = self.format_time(timedelta(hours=12))
        while (self.talks):
            print('Track {}\n'.format(self.Track))
            O.write('Track {}\n'.format(self.Track))
            end_morning_session = self.plan(9, 12, O)
            print('{}  {} '.format(lunch, ' Lunch\n'))
            O.write('{}  {} '.format(lunch, ' Lunch\n'))
            end_afternoon_session =self.plan(13, 17, O)
            print('{}  {}'.format(end_afternoon_session, 'Networking Event\n'))
            O.write('{}  {}'.format(end_afternoon_session, 'Networking Event\n'))
            self.Track += 1
        
        O.close()
                                
if __name__ == '__main__':
    P = Conference()
    P.print_plan()

TestConference.py

import unittest
import conference as c
from datetime import timedelta, datetime
import io
from unittest.mock import mock_open, patch
from mock_open.mocks import MockOpen, FileLikeMock
import os

try:
    # pylint: disable=no-name-in-module
    from unittest.mock import patch, call, NonCallableMock, DEFAULT
except ImportError:
    from mock import patch, call, NonCallableMock, DEFAULT


class TestConference(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print('setupClass')
        
    @classmethod
    def tearDownClass(cls):
        print('tearDownClass')
        
    def setUp(self):
        print('setUp')
        f = open('input.txt')
        self.lines={line.strip('') for line in f}
        f.close()
        
    def test_proposals_extract(self):
        """Check effects of reading from an empty file."""
        myclass_instace = c.Conference()
        handle = open(myclass_instace.inputs, 'r')
        self.assertFalse(handle.closed)
        self.assertEqual('input.txt', handle.name)
        self.assertEqual('r', handle.mode)
        self.assertEqual(0, handle.tell())
        text = handle.read()
        self.assertNotEqual(0, handle.tell())
        self.assertNotEqual('', text)
        handle.close()
        self.assertTrue(handle.closed)
        talks = myclass_instace.proposals_extract()
        self.assertEqual(len(self.lines), len(talks))
        
        """Check calls made when `open` is used as a context manager."""
        with open(myclass_instace.inputs, 'r') as handle:
            self.assertFalse(handle.closed)
            self.assertEqual(myclass_instace.inputs, handle.name)
            self.assertEqual('r', handle.mode)
            self.assertEqual(0, handle.tell())
                
    def test_format_time(self):
        myclass_instace = c.Conference()
        time = myclass_instace.format_time(timedelta(hours=9))
        self.assertEqual(time,'09:00 AM')
        
    def test_plan(self):
        O = open('output.txt', 'a') 
        myclass_instace = c.Conference()
        end_session = myclass_instace.plan(9, 10, O)
        self.assertEqual(end_session,'10:00 AM')
        end_session = myclass_instace.plan(16, 17, O)
        self.assertEqual(end_session,'05:00 PM')
        O.close()
        
    def test_print_plan(self):
        myclass_instace = c.Conference()
        myclass_instace.print_plan()
        self.assertTrue(os.path.isfile(myclass_instace.outputs))
        self.assertFalse(myclass_instace.talks)

            
if __name__ == '__main__':
    unittest.main()
\$\endgroup\$

1 Answer 1

8
\$\begingroup\$

Parametric files

It would be trivially easy to have Conference accept filenames as parameters to its constructor, and will make this more usable.

Variable names

Track should be lower-case. O is a poor choice of variable name for a list of reasons:

  • It should be lowercase
  • It looks the same as a zero
  • Generally speaking, single-letter variable names are mystifying, and it's only by luck that I understand it to mean "output"

P should similarly be called plan.

Context management

Avoid opening f and O and closeing them separately; put this in a with instead. Delete your FileNotFoundError block; it does nothing useful.

Line iteration

Replace

        while True:
            line = f.readline()
            if not line:
                break   

with

for line in f:

Unpacking

Try replacing

        duration = item[1]
        proposal = item[0]

with

proposal, duration = item

assuming that there are only two items in this sequence.

Spelling

instace = instance.

Tests

This entire block:

    myclass_instace = c.Conference()
    handle = open(myclass_instace.inputs, 'r')
    self.assertFalse(handle.closed)
    self.assertEqual('input.txt', handle.name)
    self.assertEqual('r', handle.mode)
    self.assertEqual(0, handle.tell())
    text = handle.read()
    self.assertNotEqual(0, handle.tell())
    self.assertNotEqual('', text)
    handle.close()
    self.assertTrue(handle.closed)

    """Check calls made when `open` is used as a context manager."""
    with open(myclass_instace.inputs, 'r') as handle:
        self.assertFalse(handle.closed)
        self.assertEqual(myclass_instace.inputs, handle.name)
        self.assertEqual('r', handle.mode)
        self.assertEqual(0, handle.tell())

is not useful and should be deleted. You're basically testing that file IO in Python works, and spoiler alert: it does. The only valuable part of this test is when you call proposals_extract and validate its return value against known-good data.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.