Solved

python unit testing with multiple classes

Posted on 2010-11-22
27
1,307 Views
Last Modified: 2012-05-10
I have the following requirement:
"Write a function that takes two arguments, a string player name and an integer score, and keeps a "high score" table in a Python shelve. If the integer argument is higher than the given player's current high score (or if the player has no recorded high score), log the value as this player's new high score. The function should return the player's current high score.
Again, write a separate test module that verifies the operation of the function."

I wrote a function that works but have no idea how to write the test module.  In the example provided, what is tested is a library module that imports 'shelve' and contains 3 classes: a Library class to add a book and look it up by isbn number, title and author, an Author class and a Book class. The library module itself returns no values - data is added to a shelf file via the unittest module, which has functions to test the library module methods (to look up a book by author, title or isbn number).

In the attached code, I attempted to write a unittest module that mimics the lesson example, for lack of any better ideas, and of course it doesn't work...the latest error is:

self.game = players2.Player(self.game_fn, self.team, self.scores)
TypeError: __init__() takes exactly 3 arguments (4 given)

I don't know how to make the setUp method's arguments add the specified data to the shelf file.  I tried placing the function inside a class (the third attachment) and that's the only module I have written that works. Pls give me some direction on this, thanks.



# the functions to be tested:

class Library:

    def __init__(self, fn):
        pass
        self.fn = fn
        self.shelf = shelve.open(fn)
    
    def add_Player(self, team):
        pass
        self.shelf[team] = team

    def add_Score(self, team):
        pass
        self.shelf[team.scores] = team

    def close(self):
        pass
        self.shelf.close()

class Player:

    def __init__(self, team, scores):
        self.team, self.scores = team, scores

    def __eq__(self, other):
        if type(other) is type(self):
            return self.__dict__ == other.__dict__
        return False

    def __ne__(self, other):
        return not self.__eq__(other)

Open in new window

class Players:

    def __init__(self, shelf, player, score_input, score):
        self.shelf = shelve.open('shelf_scores.shlf')
        self.player = player
        self.score_input = score_input
        self.score = score

    def add_player(self, shelf):
        while True:
            msg = 'Add a player: '
            player = raw_input(msg).strip()
            if player:
                score = 0
                while True:
                    msg = 'Add a score for ' + player + ': '
                    score_input = raw_input(msg).strip()
                    if score_input.isdigit():
                        if int(score_input) > int(score):
                            print score_input, '>', score, ', new high score:', score_input
                            shelf[player] = score_input
                            score = score_input
                        else:
                            print score_input, '<',  score, ', pass'
                    else:
                        print "Score empty or not recognized, exiting player", player
                        break
            else:
                print 'No player, exiting'
                break

        Players.read_scores(self, shelf)

    def read_scores(self, shelf):
        for player in sorted(shelf.keys()):
            print 'Player', player, 'high score:', shelf[player]
        shelf.close()


if __name__ == "__main__":

    shelf = shelve.open('shelf_scores.shlf')
    player = 'Anonymous'
    score_input = 0
    score = 0
    instance = Players(shelf, player, score_input, score)
    Players.add_player(instance, shelf)
    shelf.close()

Open in new window

# the unittest:

class TestScores(unittest.TestCase):

    def setUp(self):

        self.game_fn = 'shelf_scores.shlf' 
        self.team = players2.Library('Joe', 'Sally','Jim')
        self.scores = players2.Player(10, 20, 30)       
        self.game = players2.Player(self.game_fn, self.team, self.scores)
        self.game.add_Player(self.team)
        self.game.add_Score(self.scores)
        
    def test_add_Player(self):
        observed = self.game.add_Player(self.team)
        self.assertEquals(observed, self.team)

    def test_add_Score(self):
        observed = self.game.add_Score(self.team)
        self.assertEquals(observed, self.team)
         
    def tearDown(self):
        self.game.close()

if __name__ == "__main__":
    unittest.main()

Open in new window

0
Comment
Question by:sara_bellum
  • 14
  • 11
  • 2
27 Comments
 

Author Comment

by:sara_bellum
Comment Utility
Just to clarify: attachment 1 (class Library, class Player) and attachment 3 (the unittest) are my stab at making python unit testing work, but they are wild guesses.

class Players (attachment 2) is a module that runs on its own: it contains the function to add players and scores and it actually works, although it doesn't look very efficient.
0
 
LVL 14

Expert Comment

by:jaiganeshsrinivasan
Comment Utility
hi,
being this as your INIT of Players, there are 5 arguements (including self)
def __init__(self, shelf, player, score_input, score):
but in your call there is only 3 parameters passed...

self.game = players2.Player(self.game_fn, self.team, self.scores)
you must pass 4 arguements ...and tht is what the error says...
0
 
LVL 14

Expert Comment

by:jaiganeshsrinivasan
Comment Utility
sorry...wrong pointer...(from your PLAYER class)
def __init__(self, team, scores):
it accepts only 2 parameters...and you have passed 3...so the error...
0
 

Author Comment

by:sara_bellum
Comment Utility
To keep it simple the unittest module is now only testing methods from a single class (Library) from the imported module (player2).
self.game is looking for a matching number of init arguments in class Library:

   def setUp(self):
        self.game_fn = 'shelf_scores.shlf'
        self.team = players2.Library('Joe', 'Sally','Jim')
        self.scores = players2.Library('10', '20', '30')  
        self.game = players2.Library(self.game_fn, self.team, self.scores)      
        self.game.add_Player(self.team)
        self.game.add_Score(self.scores)
       
    def test_add_Player(self):
        observed = self.game.add_Player(self.team)
        self.assertEquals(observed, self.team)

    def test_add_Score(self):
        observed = self.game.add_Score(self.team)
        self.assertEquals(observed, self.team)

and the imported (players2) module now shows

class Library:

    def __init__(self, fn, team, scores):
        pass
        self.fn = fn
        self.shelf = shelve.open(fn)
        self.team = team
        self.scores = scores
   
    def add_Player(self, team):
        pass
        self.shelf[team] = team

    def add_Score(self, team):
        pass
        self.shelf[team.scores] = team

Now the error is this:

File "./players_test.py", line 15, in setUp
    self.game.add_Player(self.team)
  File "/path-to-module/players2.py", line 16, in add_Player
    self.shelf[team] = team
  File "/usr/lib/python2.6/shelve.py", line 132, in __setitem__
    p.dump(value)
  File "/usr/lib/python2.6/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle DB objects

----------------------------------------------------------------------
Ran 2 tests in 0.079s

Pls explain the error and point me in the right direction thanks.
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Just a note, the setUp() and tearDown() should be used only in cases when you cannot avoid that.  The goal of unit tests is to separate the tested functionality.  It is usual to do everything in the single test, including creation of the tested objects.

You know better the task.  From the question, it seems to me that the "high score" table should be kept with the Player, not inside a Library class.  In my opinion, all the things should be in the Player class.  The Player class instance should keep the name of the player, not of the team.  This way the name of the player could be used for construction of the file that stores the "high score" for that player.

I suggest to make clear what is the goal.  Then, it is a good opportunity to try "write tests first" approach.  The iterative development that uses unit testing ("test driven development") often starts with the simplified task (write test for the simplified task, then write the implementation).  Later, new functionality is added (written new tests, then implementation of the new functionality).

For longer run, I recommend to read the Dive Into Python 3 by Mark Pilgrim, chapter 9. Unit Testing (http://diveintopython3.org/unit-testing.html).
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Another observation.  The text says "Write a FUNCTION...".  Are you sure that there should be the Player class.  It seems to me that you should write a module with the module variable -- the dictionary where the player name is the key and say the ordered list that keeps the score for the key.  That single dictionary should be shelved...

Is the task just your personal choice or do you follow some training?
0
 
LVL 28

Accepted Solution

by:
pepr earned 500 total points
Comment Utility
I may be wrong.  Anyway, have a look at the following example (from scratch).  Let the module with the wanted functionality is called score (i.e. score.py) and the wanted function is called set().  The following implementation is the initial one.  Actually, it does not solve the task.  The shelve is not used at all.  However, it has the correct interface that the test will use:

score.py
scoreTable = {}

def set(name, score, d=scoreTable):
    return None

Open in new window


Now the initial test will contain only a single test (to start somehow) that tests a single feature of the wanted solution.  Here the test checks whether the set() function returns always the highest score for the player.

test.py
import score
import unittest

class TestScores(unittest.TestCase):

    def test_scoreSet_returnHighest(self):
        result = score.set('Jan', 1)    # first value
        self.assertEqual(result, 1)
        
        result = score.set('Jan', 2)    # second value is bigger
        self.assertEqual(result, 2)
        
        result = score.set('Jan', 1)    # third value is smaller...
        self.assertEqual(result, 2)     # ... the second is higher
        

if __name__ == '__main__':
    unittest.main()

Open in new window


You may notice that the test.py is also implemented only partially.  When writing other tests, you will learn what functionality and what interface the score.py must support.  It is better to follow the needs of the tests than to try to guess.
0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
When running the test, you get something like this:

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
F
======================================================================
FAIL: test_scoreSet_returnHighest (__main__.TestScores)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 8, in test_scoreSet_returnHighest
    self.assertEqual(result, 1)
AssertionError: None != 1

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)


From this you know what failed and what should be implemented.
0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
Now you know that the set() function must be enhanced.  Let's do the following

score.py
scoreTable = {}

def set(name, score, d=scoreTable):
    
    # Get the highScore list for the name (or list with a single given score).
    highscore = d.setdefault(name, [ score ])
    
    # If the given score is higher, insert it.
    if score > highscore[0]:
        highscore.insert(0, score)
    
    # Return the highest score for the name.
    return highscore[0]

Open in new window



Now the test runs like that

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK


This means that you should stop coding.  The implementation passed.

The problem is that it still does not solve the task.  But the next step is to write more tests first and only then the implementation.
0
 

Author Comment

by:sara_bellum
Comment Utility
Thanks pepr, it was good to see all your postings when I got started today! I'm trying to meet a course requirement, and for some time thought I'd never understand this in a million years. But once you broke it down into manageable pieces I began to understand :)  I attach what works so far and will take a break now...


scores.py:

def set(shelf, names, numbers, base_score):

    for name in names:
        for score in numbers:
            if score > base_score:
                shelf[name] = score 
                base_score = score                
            else:
                shelf[name] = base_score 
                
    print 'Shelf:', shelf
    return score

Open in new window

# test_scoring.py:

shelf = shelve.open('player_scores.shlf')
base_score = 0
names = ['Bill','Mary','Joe', 'Sally']
numbers = [10,20,15,25]

class TestScores(unittest.TestCase):
       
    def test_set(self):

        result = scores.set(shelf, names, numbers, base_score)   
        self.assertEqual(result, 25)
        
        shelf.close()
	
if __name__ == '__main__':
    unittest.main()

Open in new window

0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
Well, as far as I understand the task, each of the players should have his/her own list of high scores.  The shelf should be common for all players (all players in one file).  This way you really need to bound 'name' to some structure of several numbers.  The structure probably should be the list as it keeps the order.  You want it to keep the order because then it is easy to find the highest score.  These are the reasons why I have chosen the dictionary object for that purpose.

If this is the case, your three structures (two arrays and one base_score) are not enough.

If the problem is to be taken more seriously (i.e. what is usually wanted/needed), then you want to implement it so that the interface to the functionality would be as simple as possible.  This also mean that you never want to take care of the shelf.  You do not want to open it explicitly before the set() function is used and you do not want to take care if it is closed or not or whatever.

Have a closer look at the shelve module documentation (http://docs.python.org/library/shelve.html#module-shelve).  The very first sentence says:
A “shelf” is a persistent, dictionary-like object.
 With respect to the above, it is exactly what you want to use instead of the scoreTable dictionary that was shown above.  I will show you the next step later...

Anyway, some comments for your solution.  You never update the numbers array.  This way, it can never work correctly or the numbers is not needed.  The test_scoring.py should not work with the .shlf file.  It must be done only through the scores.py.
0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
(I hope that this is not a homework that you should do alone.)  The following is the modification of score.py that I wrote earlier.  It adds the automatic usage of the shelve module to make the table persistent.

score.py
import shelve

# The open of the shelve can be done automatically when the module is imported.
scoreTable = shelve.open('scores.shlf', writeback=True)


# The close of the scoreTable cannot be done automatically.
def tableClose():
    scoreTable.close()
    

def set(name, score, shelf=scoreTable):

    # Get the highScore list for the name (or list with a single given score).
    highscore = shelf.setdefault(name, [ score ])
    
    # If the given score is higher, insert it.
    if score > highscore[0]:
        highscore.insert(0, score)
    
    # Always synchronize the shelf.
    shelf.sync()
    
    # Return the highest score for the name.
    return highscore[0]

Open in new window


Notice that there are only few modifications.  The tableScore is now the shelf instead of the plain dictionary.  However, it behaves as dictionary, so the code in the set() function need not to be changed too much.  The only modification is that after each set() the shelf.sync() is called to propagate the possible changes to the file.

Another difference is introduction of the tableClose() function of the score.py module as the shelf should be closed (i.e. its file should be closed) when you stop to use it.  In the test.py, the tableClose() is called via the tearDown() method.  This is the example of the case when the test helps to design the interface of the tested module.  Think about the later usage of the score.py.  Actually, the test.py can be viewed as an application that uses the score.py.  This way, when writing tests, you meet the various situations that may happen later your real application that will use the score.py.  Because of this the approach "write tests first" may help to develop everything faster even though it seems that one is doing some unneccessary extra work.  This case is not that apparent.  We will see better example a bit later:

test.py
import score
import unittest

class TestScores(unittest.TestCase):

    def tearDown(self):
        score.tableClose()

    def test_scoreSet_returnHighest(self):
        result = score.set('Jan', 1)    # first value
        self.assertEqual(result, 1)
        
        result = score.set('Jan', 2)    # second value is bigger
        self.assertEqual(result, 2)
        
        result = score.set('Jan', 1)    # third value is smaller...
        self.assertEqual(result, 2)     # ... the second is higher
        

if __name__ == '__main__':
    unittest.main()

Open in new window


Let's run the test:

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.085s

OK

"Jupeeee, it works! Let's show it to my teacher..."

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
F
======================================================================
FAIL: test_scoreSet_returnHighest (__main__.TestScores)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 11, in test_scoreSet_returnHighest
    self.assertEqual(result, 1)
AssertionError: 2 != 1

----------------------------------------------------------------------
Ran 1 test in 0.037s

FAILED (failures=1)


"Grrrr.  What happened?  It worked!"

Do you know the reason?  What is broken?  (Hint: Try to erase the score.shlf first.)



0
 

Author Comment

by:sara_bellum
Comment Utility
Once again pepr this is genius - I added os.remove(fn) to score.py's table.close() method and all was well.  

But I still don't understand how to specify desired results in unittest modules to measure the success of the functions I am testing. For example, another module I wrote works as intended when I add commands to execute each function at the end of the module. But when I try to execute the same functions from the unittest module they fail with errors. My module, unittest module and testing results are attached.

I copy the requirement that I was trying to meet:
"Write a module containing a function to examine the contents of the current working directory and print out a count of how many files have each extension (".txt", ".doc", etc.) Write a separate module to verify by testing that the function gives correct results. "

On this iteration I didn't bother with the count until I was finished printing the filenames so maybe I'm trying to bite off more than I can chew:  since there were 41 files in the directory, I wasn't keen on specifying a matching result for each of the 41 files (and I don't know how to do that). But I knew that the print statement was giving me the correct filenames and counts on stdout, so I tried to find a way to capture the output in the unittest module as a single result (rather than 41 result files + result count numbers for each file type). But it doesn't work.

After Thanksgiving I'll try to just get the counts tested via the unittest module. In the meantime, it's so much easier to write a series of functions and test them independently of the unittest module that I'm having difficulty understanding how or why unittest is useful at all :(

./project3.py 
Files are listed by file extension.
txt: rw.txt
py: project5.py
py: test_scores.py
...etc...

The number of text files is 1
The number of csv files is 0
The number of py files is 21
The number of other files is 19
And the total number of files is 41.

F.F
======================================================================
FAIL: test_print_file (__main__.TestFiles)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./project3.py", line 19, in test_print_file
    self.assertEqual(action, result)
AssertionError: None != <closed file 'rw.txt', mode 'r' at 0xb76d6498>

======================================================================
FAIL: test_write_lists (__main__.TestFiles)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./project3.py", line 13, in test_write_lists
    self.assertEqual(action, result)
AssertionError: None != <closed file 'rw.txt', mode 'r' at 0xb76d6498>

----------------------------------------------------------------------
Ran 3 tests in 0.003s

Open in new window

# the module to be tested:

f  = 'rw.txt'
fa = open('rw.txt', 'a') 
fr = open('rw.txt', 'r')

def write_lists(fa):
    txt_list = []
    csv_list = []
    py_list = []
    any_list = []
    fa.write("Files are listed by file extension.\n")
    for filename in os.listdir(os.getcwd()):
        name, extension = os.path.splitext(filename)
        if extension == '.txt':
            txt_list.append(filename)        
        elif extension == '.csv':
            csv_list.append(filename)         
        elif extension == '.py':
            py_list.append(filename)            
        else:
            any_list.append(filename)
              
    for filename in txt_list:
	fa.write('txt: ' + filename + '\n')
    for filename in csv_list:
        fa.write('csv: ' + filename + '\n')
    for filename in py_list:
        fa.write('py: ' + filename + '\n')
    for filename in any_list:
        fa.write('other: ' + filename + '\n')

    fa.write("\nThe number of text files is " + str(len(txt_list)))
    fa.write("\nThe number of csv files is " + str(len(csv_list))) 
    fa.write("\nThe number of py files is " + str(len(py_list)))
    fa.write("\nThe number of other files is " + str(len(any_list)))

    total = len(txt_list) + len(csv_list) + len(py_list) + len(any_list)   
    
    fa.write("\nAnd the total number of files is %s. \n\n" %str(total))
    fa.close()

def print_file(fr):
    for line in fr:
        line = line.strip()
        print line
    fr.close()

def tearDown(f):
    
    if os.path.isfile(f):
        #print f, 'is a file'
        try:
            os.remove(f)        
        except OSError:
            print 'File not found:', f, '\n'
            pass

#write_lists(fa)
#print_file(fr)
#tearDown(f)

Open in new window

# the test module

import unittest
import file_types #the module to be tested
import os

class TestFiles(unittest.TestCase):

    def test_write_lists(self):     
        action = file_types1.write_lists(file_types1.fa)
        result = file_types1.fr
        self.assertEqual(action, result)

    def test_print_file(self):
        action = file_types1.print_file(file_types1.fr)
        result = file_types1.fr
        self.assertEqual(action, result)           
        
    def test_tearDown(self):
        file_types1.tearDown(file_types1.f)

if __name__ == "__main__":
    unittest.main()

Open in new window

0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 28

Expert Comment

by:pepr
Comment Utility
For the score example
I added os.remove(fn) to score.py's table.close() method and all was well.
Well, this may not be what is wanted as you probably do not want to remove the .shlf file in the real usage.  What is broken here is the test.  The test should prepare the situation for testing the functionality.
But I still don't understand how to specify desired results in unittest modules to measure the success of the functions I am testing.
The unit tests were invented for testing the tiny bits of the implemented functionality.  You do not want to use the unit tests for testing the whole application.  The key of the design is always to build more complex things out of the less complex things.  The unit tests were designed for testing the building blocks.

Think in terms that you prepare some functions for someone else.  The one wants some functionality described somehow.  The unit test should capture that functional description.  Each unit test should be (if possible) focused on a single feature, single function, etc. -- i.e. it should separate the smallest possible part of the important functionality and test it independently on the other parts of the functionality.

Each functionality has its own assumptions: what must be passed as input, what should it do, how to behave when something wrong happes (bad input, bad environment...).

This way you approach to writing your code as a library of functions to be used by other people (even though you may use it alone).  This means that you also have to recognize important chunks of the functionality and make them separate functions/classes/module/whatever.

Think about unit tests as about a program that uses the library designed by you.  In other words, the unit tests use your library of functions -- only slightly differently than the final application that will also use your library.  This way, you will finally have two applications:  the wanted final application, and the testing application.  It is easier to build a final application out of the bigger building blocks than from the many (not aggregated) sequences of commands).  The probability that the final application works is much bigger if you know that the building blocks are correct.  The unit tests are here to test the building blocks.  As the unit tests are developed together with the building blocks, they capture all the (wrong and good) situations that you met when developing the the building blocks.  You probably never throw away the existing unit tests.

This means that you can always test your building blocks later when you do some modifications of the building blocks (to check whether some (say) optimization did not break anything).

Now back to the earlier score example.  The test is broken.  The reason is that it assumes that you always start with empty table.
However, the table is persistent (stored in a file) and it can be filled earlier.  Therefore, the test should reflect the situation.  The modification is not difficult.  First, get the highest score for the person by setting whatever value.  The use a bit higher values for testing instead of the constants.  Here is the modified test:
import score
import unittest

class TestScores(unittest.TestCase):

    def tearDown(self):
        score.tableClose()

    def test_scoreSet_returnHighest(self):
        start = score.set('Jan', 1)    # could be first value but need not to be
        
        # Now we have the highest score of Jan. The test will modify his table.
        result = score.set('Jan', start + 1)  # this must be new highest score
        self.assertEqual(result, start + 1)
        
        result = score.set('Jan', start + 2)    # second value is bigger
        self.assertEqual(result, start + 2)
        
        result = score.set('Jan', start + 1)    # third value is smaller...
        self.assertEqual(result, start + 2)     # ... the second is higher
        

if __name__ == '__main__':
    unittest.main()

Open in new window


And what it shows when you run the test several times?

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.143s

OK

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.103s

OK

c:\tmp\___python\sara_bellum\Q__26632867>python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.098s

OK

For the second example... later.
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Some comments for project3.py.  You probably do not want to name any of your functions in a solution as tearDown().  Let it for the unit tests.

I will start from scatch discussing the requirements first...
Write a module containing a function to examine the contents of the current working directory and print out a count of how many files have each extension (".txt", ".doc", etc.) Write a separate module to verify by testing that the function gives correct results.
It seems to be quite dense requirement. Almost each word is important:

1. Write a module

So, this is clear. It should be the module -- here you have project3.py

2. that contains a function

This means that you have to define a function, and you have to invent some good name for it.

3. to examine the contents of the current working directory

This is clear. With respect to the point 4 this could be a simplification of the more general "of a given directory".

4. and print out

It is difficult to test a function that manifests itself only by side effects (like printing). Because of that I do recommend to think about two functions. The first one will examine the directory (passed via its argument), the second will print the result only.  The printing is easy enough to be sure it works.  The first one will be easier to test.  Moreove, it may be desirable to have a function that works silently, without printing.  So, the core function need not to be only some auxiliary one, but it can be a function wanted by some users.

5. a count of how many files have

With respect to point 4, it describes the core function, not the printing capability.  The word files is also important as the directory can also contain subdirectories, not only the files.

6. each extension

This says nothing about the wanted extensions. Therefore, you have to make it general, without putting the hardwired constants (i.e. nothing like .txt, .doc, and the rest). There even can be files with no extension (empty extension).

7. Write a separate module

Let's call its file the test_project3.py.

8. to verify by testing that the function gives correct results.

Unit testing is good for that. To verify means try many cases, namely the cases like: empty directory, directory with subdirectory, single file, all files with the same extension, each extension once, arbitrary number of each extension.
The next about "write tests first" later.
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Starting with steps 1, 7, and 8.

Let's create the empty file project3.py (now we have the module) and the file test_project3.py with the minimal content.  Let's test only that we have the wanted function -- which is not true, yet.

test_project3.py
import project3   # the module to be tested
import unittest

class TestProject3(unittest.TestCase):

    def test_callOnly(self):
        '''Calling the wanted function, just checking its existence.'''
        project3.printCwdFilesByExtensionCounts()
            

if __name__ == '__main__':
    unittest.main()

Open in new window


Notice that the wanted function was named printCwdFilesByExtensionCounts().  Notice it has no arguments and we do not process its return value at all.  Let's try to run the test:

C:\tmp\_Python\sara_bellum\Q__26632867>python test_project3.py
E
======================================================================
ERROR: test_callOnly (__main__.TestProject3)
Calling the wanted function, just checking its existence.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_project3.py", line 8, in test_callOnly
    project3.printCwdFilesByExtensionCounts()
AttributeError: 'module' object has no attribute 'printCwdFilesByExtensionCounts'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)


Here we have the first result.  Notice also that the documentation string of the test method was displayed just under the ERROR: line.  Put the meaningfull string here that describes the test purpose.  You can use a multiline string but only the first line is displayed.

The error says that the function was not implemented at all.  It does not exist.  Let's fix it and run the same test again.

project3.py
def printCwdFilesByExtensionCounts():
    '''Prints the counts of the files grouped by their extensions.'''

Open in new window


Notice the extreme brevity.  Notice that the documentation string can replace the empty body.   No need to use the pass command here.  What the test says now:

C:\tmp\_Python\sara_bellum\Q__26632867>python test_project3.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
0
 

Author Comment

by:sara_bellum
Comment Utility
ok first let me say that I'm honored that you would spend so much time trying to coach me through this pepr - it's a particular irony given that there is an online instructor for the course I'm taking, whose job it is to reject anything that doesn't work without explanation. I suppose I could have saved myself some money by working with a book instead but had hoped for more interaction. The course exercises - and your comments - are challenging, so there's really nothing for me to complain about :)

It will take some time for me to understand your suggestions well enough to  incorporate them into my code, but something did sink in because at least on project 3, some of your corrections (stick to verifiable numbers on the unit test) are working, so I attach those files. I left the tearDown function in there because it was part of the example we were expected to follow I think, and omitted the setUp function because quite honestly I don't understand it; we'll see if I pass the objective for this exercise but I'm much less concerned about passing the course than I am about making progress.

Hope to get back to scores.py tomorrow...


# project3.py

import unittest
import file_types #the module to be tested
import os

class TestFiles(unittest.TestCase):

    def test_make_lists(self):     
        for filename in os.listdir(os.getcwd()):
            file_types.make_lists(filename)
        self.assertEqual(len(file_types.txt_list), 1)
        self.assertEqual(len(file_types.py_list), 22)
        self.assertEqual(len(file_types.any_list), 12)

    def test_write_lists(self):  
        file_types.write_lists(file_types.txt_list, file_types.py_list, file_types.any_list, file_types.fn)
        self.assertEqual(file_types.total[0], 35)           
        
    def test_tearDown(self):
        file_types.tearDown(file_types.f)

if __name__ == "__main__":
    unittest.main()

///////////////////////

$ ./project3.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Open in new window

#file_types.py

import os

txt_list = []
csv_list = []
py_list = []
any_list = []
total = []
fn = open('rw.txt', 'w')    
f  = 'rw.txt'

def make_lists(filename):
    
    name, extension = os.path.splitext(filename)
    if extension == '.txt':
        txt_list.append(filename)        
    elif extension == '.csv':
        csv_list.append(filename)         
    elif extension == '.py':
        py_list.append(filename)            
    else:
        any_list.append(filename)

    return txt_list, py_list, any_list


def write_lists(txt_list, py_list, any_list, fn):
         
    fn.write('Files are listed by file extension.\n')     
    
    for filename in txt_list:
	fn.write('txt: ' + filename + '\n')
    for filename in csv_list:
        fn.write('csv: ' + filename + '\n')
    for filename in py_list:
        fn.write('py: ' + filename + '\n')
    for filename in any_list:
        fn.write('other: ' + filename + '\n')

    fn.write("\nThe number of text files is " + str(len(txt_list)))
    fn.write("\nThe number of csv files is " + str(len(csv_list))) 
    fn.write("\nThe number of py files is " + str(len(py_list)))
    fn.write("\nThe number of other files is " + str(len(any_list)))

    count = len(txt_list) + len(csv_list) + len(py_list) + len(any_list) 
    total.append(count) 
     
    fn.write("\nAnd the total number of files is %s. \n\n" %str(count))
    return total

def print_file(fr):  
    for line in fr.readlines():
        line = line.strip()
        print line
      
def tearDown(f):
    
    if os.path.isfile(f):
        try:
            os.remove(f)        
        except OSError:
            print 'File not found:', f, '\n'
            pass

def main():
       
    for filename in os.listdir(os.getcwd()):
        make_lists(filename)
    
    write_lists(txt_list, py_list, any_list, fn)
    fn.close()
    
    fr = open('rw.txt', 'r')
    print_file(fr)
    fr.close()

    tearDown(f)

#if __name__ == "__main__":
    #main()

Open in new window

0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
Still, should not be the tearDown() the part of the unit testing code?  The purpose of the methods is not that difficult to explain.  Your TestFiles class is the descendant of the unittest.TestCase class.  The unittest.main() is actually a class that looks like a function.  When the object of the class is created (via "calling" the class unittest.main), it activates itself.  Then it takes all the TestCase based class and searches for all methods with the identifiers prefixed by "test".  The test methods are launched one by one (independently on each other) and the results are collected and reported.

The purpose of the setUp() and tearDown() is to prepare the environment for running each of the tests.  The setUp() is always called before calling one of the tests, the tearDown() is called after the test was executed.  This way, you want to use setUp() for actions that must be done (from scratch) before the test, and you want to use the tearDown() to clean up the environment after the test was run.

For testing the project3, you may want to write more tests.  You need to generate different situations for each of the tests.  This way, the setUp() may not be that suitable for you if you use only one class based on TestCase.  You could use more classes based on TestCase.  Then each of the classes could have specific setUp().  However, it is probably easier to write your own method (not prefixed "test") that will generate the data for testing and call it with some parameters at the beginning of each of the tests.

The setUp() method could be used for remembering current working directory, creating the testing directory, and switching to that directory (changing the current working directory).  The tearDown() could be used for switching back to the previous working directory and cleaning the testing directory.  Something like that:

import file_types
import os
import shutil
import unittest

class TestFiles(unittest.TestCase):

    def setUp(self):
        self.saved_cwd = os.getcwd()  # remember cwd for switching back in tearDown
        self.testdir = os.path.abspath('testdir')  
        if not os.path.isdir(self.testdir):  # create the subdir if not present 
            os.makedirs(self.testdir)
        os.chdir(self.testdir)               # change the working directory
            
    
    def tearDown(self):
        os.chdir(self.saved_cwd)             # back to the original subdir
        if os.path.isdir(self.testdir):
            shutil.rmtree(self.testdir)      # clean up

            
    def genTestFiles(self, d):
        '''Generates the number of the test files with the extensions.
        
        The d is a dictionary in the form {'.txt': 1, '.py': 22, '.any': 12}'''
        for ext in d:
            for n in xrange(1, d[ext] + 1):
                fname = 'file%03d%s' % (n, ext)
                f = open(fname, 'w')
                f.write('test file ' + fname)
                f.close()


    def test_make_lists(self):     
        self.genTestFiles({'.txt': 1, '.py': 22, '.any': 12})
        for filename in os.listdir('.'):  
            file_types.make_lists(filename)
        self.assertEqual(len(file_types.txt_list), 1)
        self.assertEqual(len(file_types.py_list), 22)
        self.assertEqual(len(file_types.any_list), 12)


    def test_write_lists(self):  
        self.genTestFiles({'.txt': 1, '.py': 22, '.any': 12})
        file_types.write_lists(file_types.txt_list, 
                               file_types.py_list, 
                               file_types.any_list, 
                               file_types.fn)
        self.assertEqual(file_types.total[0], 35)           
            
        
if __name__ == '__main__':
    unittest.main()

Open in new window


Study the setUp(), tearDown(), and genTestFiles().  Notice how the self.genTestFiles() is called at the beginning of your tests.  Together with tearDown(), always the fresh set of testing files is generated at the beginning of each test (explicitly).  Try to rename the tearDown and you will see the "tesdir" subdirectory with the generated content.
0
 

Author Comment

by:sara_bellum
Comment Utility
ok, starting with the project to list files by file type, I attach my latest - there are two tests now and it passes. The dictionary is not the same as yours and probably less efficient, but I try to avoid copying code when I can write my own.

The project to keep a record of player high scores works better than before. The highscore dictionary format is something I am not familiar with, but I cannot see an alternative to copying your code: each player key has to have a list of scores for its value - this is something I've never done before but I think I could do this now. I attach my latest scoring module and test module. I'm still getting errors on tearDown():

File "./test_scoring.py", line 50, in tearDown
    os.chdir(self.saved_cwd)             # back to the original subdir
AttributeError: 'TestScores' object has no attribute 'saved_cwd'

File "./test_scoring.py", line 52, in tearDown
    if os.path.isdir(self.testdir):
AttributeError: 'TestScores' object has no attribute 'testdir'

In some of my tests, a test directory was created, in others (as here) it was not, but I simply copied your code so I can't find the error. Also the filename 'scores.shlf' is never stored in the test directory, probably because I'm not able to change directories via the unittest setUp() method.

This has been a very long discussion, but very worthwhile for me!

# file_types.py

import os

txt_list = []
csv_list = []
py_list = []
any_list = []
total = []
files_dict = {}
fn = open('rw.txt', 'w')
f  = 'rw.txt'

def build_dict():

    for filename in os.listdir('.'):
        if os.path.isfile(filename) and not filename.endswith('~'):
            name, extension = os.path.splitext(filename)

            if extension not in ['.txt', '.csv', '.py']:
                extension = '.other'

            if extension not in files_dict:
                files_dict[extension] = {}

            if name not in files_dict:
                files_dict[extension][name] = {}

            files_dict[extension][name] = filename

    return files_dict

def build_lists(filename):

    if os.path.isfile(filename) and not filename.endswith('~'):
        name, extension = os.path.splitext(filename)
        if extension == '.txt':
            txt_list.append(filename)
        elif extension == '.csv':
            csv_list.append(filename)
        elif extension == '.py':
            py_list.append(filename)
        elif not filename.endswith('~'):
            any_list.append(filename)

        count = len(txt_list) + len(csv_list) + len(py_list) + len(any_list)
        total.append(count)

    return txt_list, py_list, any_list, total

Open in new window

# scoring.py

import shelve
import os

fn = 'scores.shlf'
scoreTable = shelve.open(fn, writeback=True)

def setScore(name, score, scoreTable):

    # Get the highScore list for the name (or list with a single given score).
    highscore = scoreTable.setdefault(name, [ score ])

    # If the given score is higher, insert it.
    if score > highscore[0]:
        highscore.insert(0, score)

    # Always synchronize the shelf.
    scoreTable.sync()

    # Return the highest score for the name.
    return name, highscore[0]

def tableRead(name):

    print scoreTable

    for name in scoreTable.keys():
        scores = scoreTable[name]
        print 'Player', name, 'high score:', scores[0]

    scoreTable.close()

def tableClose():

    if os.path.exists(fn):
        os.remove(fn)
    else:
        print fn, 'not found'
        pass

def main():
    while True:
        msg = 'Add a player: '
        name = raw_input(msg).strip()
        if name:
            score = 0
            while True:
                msg = 'Add a score for ' + name + ': '
                score = raw_input(msg).strip()
                if score.isdigit():
                    score = int(score)
                    setScore(name, score, scoreTable)
                else:
                    print "Score empty or not valid, exiting player", name
                    break
        else:
            print "Player empty or not valid, exiting program"
            break

    tableRead(name)
    tableClose()

#if __name__ == "__main__":
    #main()

Open in new window

# project3.py

import unittest
import file_types #the module to be tested
import os

class TestFiles(unittest.TestCase):

    def test_build_lists(self):

        for filename in os.listdir('.'):
            file_types.build_lists(filename)
        self.assertEqual(len(file_types.txt_list), 2)
        self.assertEqual(len(file_types.py_list), 9)
        self.assertEqual(len(file_types.any_list), 2)
        self.assertEqual(file_types.total[-1], 13)

    def test_write_file(self):

        files_dict = file_types.build_dict()

        fn = open('rw.txt', 'w')

        fn.write('\nDictionary files listed by extension:\n')
        count = 0
        for extension in files_dict.keys():
            fn.write("\nFile names with extension '" + extension + "': \n")
            for name in sorted(files_dict[extension]):
                fn.write(files_dict[extension][name] + '\n')
                count += 1
            fn.write("Number of files with extension '" + extension + "': " + str(len(files_dict[extension])) + "\n")
        fn.write("\nTotal number of files: " + str(count) + "\n\n")
        self.assertEquals(len(files_dict['.txt']), 2)
        self.assertEquals(len(files_dict['.py']), 9)
        self.assertEquals(len(files_dict['.other']), 2)
        self.assertEqual(count, 13)

if __name__ == "__main__":
    unittest.main()

Open in new window

# test_scoring.py

import os
import scoring
import unittest
import shelve
import shutil

class TestScores(unittest.TestCase):

    def test_setUp(self):

        self.saved_cwd = os.getcwd()
        self.testdir = os.path.abspath('testdir')
        if os.path.isdir(self.testdir):
            print 'self.testdir exists'
        else:
            print self.testdir, 'does not exist: create it'
            os.mkdir(self.testdir)

    def test_setScore(self):

        if os.path.exists(scoring.fn):
            print 'removing shelf file'
            os.remove(scoring.fn)

        result1 = scoring.setScore('Bill', 11, scoring.scoreTable)
        self.assertEqual(result1, ('Bill', 11))

        result2 = scoring.setScore('Bill', 32, scoring.scoreTable)
        self.assertEqual(result2, ('Bill', 32))

        result3 = scoring.setScore('Bill', 30, scoring.scoreTable)
        self.assertEqual(result3, ('Bill', 32))

        result4 = scoring.setScore('Mary', 21, scoring.scoreTable)
        self.assertEqual(result4, ('Mary', 21))

        result5 = scoring.setScore('Mary', 22, scoring.scoreTable)
        self.assertEqual(result5, ('Mary', 22))

        result6 = scoring.setScore('Mary', 10, scoring.scoreTable)
        self.assertEqual(result6, ('Mary', 22))

        #print scoring.scoreTable
        scoring.scoreTable.close()

    def tearDown(self):

        os.chdir(self.saved_cwd)             # back to the original subdir

        if os.path.isdir(self.testdir):
            os.listdir(self.testdir)
            print 'removing test dir'
            shutil.rmtree(self.testdir)      # clean up

if __name__ == '__main__':
    unittest.main()

Open in new window

0
 

Author Comment

by:sara_bellum
Comment Utility
I made a couple of corrections: in scoring.py, I moved scoreTable.close() from tableRead(name) to the tableClose() method. In test_scoring.py, I moved scoring.scoreTable.close() back to the tearDown() method, since I trust that I'll get setUp and tearDown working at some point. (I had shifted things around earlier to make sure that the score table was being closed.)
0
 

Author Comment

by:sara_bellum
Comment Utility
I made another correction, this one to project3.py which tests file_types.py: the filename that is used to write the test results is now listed in the project3.py unit test module as file_types.fn (not fn): the file is defined only once, and imported from the module that is being tested.
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Well, it does not make sense to remove the file in the tableClose().  The only place where it does make sense (to remove the file) is in the unittest program when you want to start checking from scratch.

The high scores as dictionary:  In my opinion, you need the list (or any other ordered structure) of results.  It is requested by the task.  The key is the name of the player.

What I do not understand is why you use nested dicts in your project3 solution.  The task says that you should find the count of the files based on extension.  You should not make your solution more complex than neccessary.  Otherwise, it will become even more complex later -- error prone.
0
 

Author Comment

by:sara_bellum
Comment Utility
I got so confused about what variables get defined where! The only way to make the scores unit test work consistently was to write a module that does it all and then test it with the same variables, defined in the setUp and of course the  test_setScore methods in the unittest module.

So there's probably unnecessary duplication in the attached files but they do work on my PC (which has python 2.5) and on the Eclipse server, which uses python3.0. The only change I had to make was change 'raw_input' to 'input', and to stop checking for scores.shlf in the tearDown routine on Eclipse because it generates a series of shelf files with different extensions.

I had so many problems running these programs that there are a lot of 'if' statements in the set-up to cover them. One of the errors that showed up repeatedly in 2.5 was a database error with fn = '/testdir/scores.shlf', but the error disappeared with fn = 'scores.shlf'  So I figured that the shelf file could only be created locally in python 2.5.  In order to generate that file in the testdir, I copied scores.py and test_scores.py to the testdir and then ran os.chdir to work locally in the test directory.

I appreciate your advice on the project3 dictionary. I just checked my records and I passed the requirement (all requirements are pass/fail). I'll keep your advice in mind when I write programs in the future :) Now to figure out how to assess points...I'll submit this first and then figure that out.

# test_scores.py

#!/usr/bin/python

import os
import scores
import unittest
import shelve
import shutil
import sys

class TestScores(unittest.TestCase):

    def setUp(self):

        self.saved_cwd = os.getcwd()
        self.testdir = 'testdir'

        if os.path.exists(self.testdir):
            if os.path.isfile(self.testdir):
                os.remove(self.testdir)
            elif os.path.isdir(self.testdir):
                shutil.rmtree(self.testdir)

            print('Test directory or file exists, removing...pls try again')
            sys.exit()

        else:
            print(self.testdir, 'does not exist: create it')
            os.mkdir(self.testdir)

        self.testdir = os.path.join(self.saved_cwd, 'testdir')
        shutil.copy('scores.py', self.testdir)
        shutil.copy('test_scores.py', self.testdir)
        os.chdir(self.testdir)

        self.fn = 'scores.shlf'
        self.scoreTable = shelve.open(self.fn, writeback=True)
        self.fn = os.path.join(self.testdir, 'scores.shlf')
        if os.path.exists(self.fn):
            print('Shelf file exists at set-up:', self.fn)

    def test_setScore(self):

        result1 = scores.setScore('Bill', 11, self.scoreTable)
        self.assertEqual(result1, ('Bill', 11))

        result2 = scores.setScore('Bill', 32, self.scoreTable)
        self.assertEqual(result2, ('Bill', 32))

        result3 = scores.setScore('Bill', 30, self.scoreTable)
        self.assertEqual(result3, ('Bill', 32))

        result4 = scores.setScore('Mary', 21, self.scoreTable)
        self.assertEqual(result4, ('Mary', 21))

        result5 = scores.setScore('Mary', 22, self.scoreTable)
        self.assertEqual(result5, ('Mary', 22))

        result6 = scores.setScore('Mary', 10, self.scoreTable)
        self.assertEqual(result6, ('Mary', 22))

        print('Score table results:', self.scoreTable)

    def tearDown(self):

        scores.tableClose(self.fn, self.scoreTable, self.saved_cwd, self.testdir)

if __name__ == '__main__':
    unittest.main()

Open in new window

# scores.py 

#!/usr/bin/python

import shelve
import os
import shutil
import sys

def setScore(name, score, scoreTable):

    # Get the highScore list for the name (or list with a single given score).
    highscore = scoreTable.setdefault(name, [ score ])

    # If the given score is higher, insert it.
    if score > highscore[0]:
        highscore.insert(0, score)

    # Always synchronize the shelf.
    scoreTable.sync()

    # Return the highest score for the name.
    return name, highscore[0]

def tableRead(name, scoreTable):

    print('Score table results:', scoreTable)

    for name in scoreTable.keys():
        scores = scoreTable[name]
        print('Player', name, 'high score:', scores[0])

def tableClose(fn, scoreTable, saved_cwd, testdir):

    scoreTable.close()

    os.chdir(saved_cwd)
    for filename in os.listdir(saved_cwd):
        name, ext = os.path.splitext(filename)
        if ext == '.pyc':
            print('Removing byte code')
            os.remove(filename)

    if os.path.isdir(testdir):
        #if 'scores.shlf' in os.listdir(testdir): # several shlf file extensions appear in testdir, omit
        # print('Shelf file exists at tear-down:', fn)
        print('Removing test directory')
        shutil.rmtree(testdir)
    else:
        print('Error:', testdir, 'and/or', fn, 'not found')


def main():

    saved_cwd = os.getcwd()
    testdir = 'testdir'

    if os.path.exists(testdir):
        if os.path.isfile(testdir):
            os.remove(testdir)
        elif os.path.isdir(testdir):
            shutil.rmtree(testdir)
        print('Test directory or file exists, removing...pls try again')
        sys.exit()

    else:
        print(testdir, 'does not exist: create it')
        os.mkdir(testdir)

    testdir = os.path.join(saved_cwd, 'testdir')

    shutil.copy('scoring.py', testdir)
    shutil.copy('test_scoring.py', testdir)
    os.chdir(testdir)

    fn = 'scores.shlf'
    scoreTable = shelve.open(fn, writeback=True)
    fn = os.path.join(testdir, 'scores.shlf')
    if os.path.exists(fn):
        print('Shelf file created during set-up:', fn)

    while True:
        msg = 'Add a player: '
        name = raw_input(msg).strip()
        if name:
            score = 0
            while True:
                msg = 'Add a score for ' + name + ': '
                score = raw_input(msg).strip()
                if score.isdigit():
                    score = int(score)
                    setScore(name, score, scoreTable)
                else:
                    print('Score empty or not valid, exiting player', name)
                    break
        else:
            print('Player empty or not valid, exiting program')
            break

    tableRead(name, scoreTable)
    tableClose(fn, scoreTable, saved_cwd, testdir)

if __name__ == "__main__":
    main()

Open in new window

0
 
LVL 28

Assisted Solution

by:pepr
pepr earned 500 total points
Comment Utility
In Python, the variable is created when it is first time used at the left side of the assignment operator.

Now for the score.py and duplicating the unittest code.  The key idea is to understand that the score.py should work completely separately from the unittest.  The score module code is "used" by the module that does unit testing.

The score module can be used as a script (the main() called) or as a module (imported elsewhere and used there).  The unit testing code uses the score as a module.  It tests all its functionality EXCEPT the main().

If the score module is to be usefull as a module it must work also without the main().  The persistence (using shelve) should probably be hidden if possible.

There are at least two approaches to unit testing (can be mixed).

The first is called "black-box testing" where you consider the tested module a black box in the sense you know the interface (the function names and arguments) and its behaviour -- you pretend to know nothing about the internal implementation.  This is the case of unit test cases when following "write tests first" advice.  It must be black-box testing as the implementation does not exist, yet.

The second approach is called "white-box testing" which means you know also the implementation and you do test also the auxiliary functionality that is used for implementation of the wanted functionality.  You do that when you found the bug in the implementation and you write the test case that causes the problem.  Then you modify your faulty code to make it passing the test.

Now, ask more specific questions to solve it step by step.
0
 

Author Closing Comment

by:sara_bellum
Comment Utility
Thanks to pepr for all the support!! I declare victory to return home, running out of points to award. I don't fully understand this at this point but can, I believe, get used to it :)
0
 
LVL 28

Expert Comment

by:pepr
Comment Utility
Do not worry about the points. Just continue here if you cannot ask new question because of the lack of the points.  The only problem is that I may not notice...

Try to find the most brief and the most accurate description of a problem that you do not understand.  Because the search for a good question is sometimes more important than reading the answer.  It helps to organize your mind.
0
 

Author Comment

by:sara_bellum
Comment Utility
Thanks for your generous offer, pepr! My questions tend towards infinity and only some of them are valid. I'm under some pressure to accomplish several things at once, so I'll come back to this when I'm faced with another unittest requirement or opportunity - looking at things from a different angle usually helps. Thankfully, this record will still be here :)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Variable is a place holder or reserved memory locations to store any value. Which means whenever we create a variable, indirectly we are reserving some space in the memory. The interpreter assigns or allocates some space in the memory based on the d…
Introduction On September 29, 2012, the Python 3.3.0 was released; nothing extremely unexpected,  yet another, better version of Python. But, if you work in Microsoft Windows, you should notice that the Python Launcher for Windows was introduced wi…
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…
Learn the basics of if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now