LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-25-2014, 03:21 AM   #1
fantasy1215
Member
 
Registered: Oct 2011
Posts: 75

Rep: Reputation: Disabled
How do you write unittest code to test the code like getDateOfYesterday?


Like you write a function to return the date of yesterday,Nomatter what language we use, Let me take python language as the example,
the code as below:
Code:
def getDateOfYesterday():
    agodate      = datetime.datetime.now() + datetime.timedelta(-1)
    agodate      = "%04d%02d%02d" % (agodate.year, agodate.month, agodate.day)
    return agodate
If I want to write code to unittest this function, The way I could figure out is to hard coded the expected return value,
Like:
Code:
class Test_getDateOfYesterday(unittest.TestCase):
    def test_1(self):
        onedayago = getDateOfYesterday
        self.assertEqual("20140924", onedayago, "")
But then everytime I need to run this unittest, I have to modify the expected return date to pass this unittest.
It's tedious.
If I don't hard coded the expected return date, then I need to write another code to verify this function.
Then what if the another code has the same fault as this function has?
Could somebody explain some theory which unittest such situation?
This question has bothered me a long time.
Hope I explain the problem clearly, and Thanks in advance.
 
Old 09-25-2014, 06:52 AM   #2
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,883
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
The problem is that you've coded with an absolute string and are not considering variability of the input.

A proper unit test first examines all possible input values; including illegal values and all possible output values.

To properly unit test something you should be testing all possible input values which can be sent to that module, or the best representation of values you can conceive of and you should automate the testing better.

Two ways I might approach this, and I would use both ways for a full and complete test:
  1. Alter system date in iteration to cause the output of datetime.datetime.now() to be a broad range of values and test iteratively
  2. Replace the possible values that agodate could be with test table data and test iteratively
In all cases, you should have a table of expected results which you compare against when you write your test function.

I would use both methods, but lean more on method #2 for the following reasons. In method #1, your system is only going to accept legal dates, and providing the library function now() works, which it does, then you're always only ever going to test legal date strings and therefore fail to test illegal date strings. Using method #2 you can cause incorrect input and verify that your module rejects or does no continued harm.

Either case, in writing your test harness, you do not hard code the expected result, you instead contrive a variety of inputs as broadly defined as you can and you also code expected outputs or behaviors from the module under test and then you run the test program and generate a report.
 
Old 09-25-2014, 07:15 AM   #3
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
One solution is to add a _now argument to getDateOfYesterday, e.g.:
Code:
def getDateOfYesterday(_now=None):
    if _now is None:
        _now = datetime.datetime.now()
    _now += datetime.timedelta(-1)
    return "%04d%02d%02d" % (_now.year, _now.month, _now.day)
and then use it in tests. You can also create a separate function:
Code:
def getDateOfPrevDay(now):
    now += datetime.timedelta(-1)
    return "%04d%02d%02d" % (now.year, now.month, now.day)

def getDateOfYesterday():
    return getDateOfPrevDay(datetime.datetime.now())
and test it instead of getDateOfYesterday.

A bit more complicated approach, but one that does not require the module you are testing to be changed, is to mock datetime.datetime.now method. Unfortunately, datetime.datetime is a built-in type so you have to mock the whole thing:
Code:
import datetime
import unittest


def getDateOfYesterday():
    dt = datetime.datetime.now()
    dt += datetime.timedelta(-1)
    return "%04d%02d%02d" % (dt.year, dt.month, dt.day)


class DateTimeMock(object):

    original_datetime = datetime.datetime
    _now = original_datetime.now()

    def now(self):
        return self._now

    def setNow(self, *args, **kw):
        self._now = self.original_datetime(*args, **kw)


class TestCase(unittest.TestCase):

    def _setNow(self, *args, **kw):
        self._dt_mock.setNow(*args, **kw)

    def setUp(self):
        self._dt_mock = DateTimeMock()
        datetime.datetime = self._dt_mock

    def tearDown(self):
        datetime.datetime = self._dt_mock.original_datetime

    def testGetDateOfYesterday(self):
        self._setNow(2014, 9, 20)
        self.assertEqual('20140919', getDateOfYesterday())

        self._setNow(2013, 9, 20)
        self.assertEqual('20130919', getDateOfYesterday())


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

Last edited by mina86; 10-01-2014 at 01:09 PM.
 
1 members found this post helpful.
Old 09-25-2014, 07:53 PM   #4
fantasy1215
Member
 
Registered: Oct 2011
Posts: 75

Original Poster
Rep: Reputation: Disabled
mina86, Thanks for your patient explanation and the example code, That's really helpful, Your view open my mind and expand my view too. I really appreciate your help. Thanks again.
 
Old 09-25-2014, 08:02 PM   #5
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 11,235

Rep: Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320
Honestly, I'd just rewrite the function to return the day before the date that's passed in.

Code:
def getDateOfYesterday(today):
    agodate      = today + datetime.timedelta(-1)
    agodate      = "%04d%02d%02d" % (agodate.year, agodate.month, agodate.day)
    return agodate
And then you use it with:

Code:
getDateOfYesterday(datetime.now())
Much more versatile, and much more testable.

Last edited by dugan; 09-25-2014 at 08:06 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how do I test the return code value Glenn D. Linux - Software 2 01-28-2011 08:34 AM
What is the fastest way to compile, if none, to test android code/OS changes? archieval Linux - Mobile 0 09-17-2010 08:40 PM
LXer: Keeping score in test-driven development with Python, PyLint, unittest, doctest LXer Syndicated Linux News 0 11-12-2009 02:10 PM
Test php code on Apache backpacker Linux - Newbie 3 12-17-2005 04:14 AM
User Preferences: Use HTML code instead of vB code? (vB code is overrated) stefanlasiewski LQ Suggestions & Feedback 5 07-26-2005 01:37 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:49 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration