Python: How do I mock datetime.utcnow()?

后端 未结 5 1026
梦如初夏
梦如初夏 2020-12-30 02:24

I have the below:

from datetime import datetime

def get_report_month_key():
    month_for_report = datetime.utcnow()
    return month_for_report.strftime(\"         


        
相关标签:
5条回答
  • 2020-12-30 02:43

    What also works when patching built-in Python modules turns out to be complicated (as it is with datetime, see e.g. https://solidgeargroup.com/mocking-the-time or https://nedbatchelder.com/blog/201209/mocking_datetimetoday.html or https://gist.github.com/rbarrois/5430921) is wrapping the function in a custom one which then can be easily patched.

    So, instead of calling datetime.datetime.utcnow(), you use a function like

    import datetime
    
    
    def get_utc_now():
        return datetime.datetime.utcnow()
    

    Then, patching this one is as simple as

    import datetime
    
    # use whatever datetime you need here    
    fixed_now = datetime.datetime(2017, 8, 21, 13, 42, 20)
    with patch('your_module_name.get_utc_now', return_value=fixed_now):
        # call the code using get_utc_now() here
        pass
    

    Using the patch decorator instead of the context manager would work similarly.

    0 讨论(0)
  • 2020-12-30 02:46

    The accepted answer by dasjotre works if you don't create any datetime instances in the module you are testing. If you try to create a datetime it will create a Mock object instead of one with the expected methods on a standard datetime object. This is because it replaces the whole class definition with a mock. Instead of doing this, you can use a similar approach to create the mocked definition by using datetime as the base.

    mymodule.py

    from datetime import datetime
    
    def after_y2k():
        y2k = datetime(2000, 1, 1)
        return y2k < datetime.utcnow()
    

    test_mymodule.py

    import unittest
    import datetime
    from mock import patch, Mock
    import mymodule
    from mymodule import after_y2k
    
    
    class ModuleTests(unittest.TestCase):
        @patch.object(mymodule, 'datetime', Mock(wraps=datetime.datetime))
        def test_after_y2k_passes(self):
            # Mock the return and run your test (Note you are doing it on your module)
            mymodule.datetime.utcnow.return_value = datetime.datetime(2002, 01, 01)
            self.assertEqual(True, after_y2k())
    
            mymodule.datetime.utcnow.return_value = datetime.datetime(1999, 01, 01)
            self.assertEqual(False, after_y2k())
    
        @patch('mymodule.datetime')
        def test_after_y2k_fails(self, mock_dt):
            # Run your tests
            mock_dt.utcnow = Mock(return_value=datetime.datetime(2002, 01, 01))
            self.assertEqual(True, after_y2k())
    
            # FAILS!!! because the object returned by utcnow is a MagicMock w/o 
            # datetime methods like "__lt__"
            mock_dt.utcnow = Mock(return_value=datetime.datetime(1999, 01, 01))
            self.assertEqual(False, after_y2k())
    
    0 讨论(0)
  • 2020-12-30 02:48

    in your test file:

    from yourfile import get_report_month_key
    import mock
    import unittest
    from datetime import datetime
    
    class TestCase(unittest.TestCase):
    
        @mock.patch('yourfile.datetime')
        def test_dt(self, mock_dt):
            mock_dt.utcnow = mock.Mock(return_value=datetime(1901, 12, 21))
            r = get_report_month_key()
            self.assertEqual('190112', r)
    
    0 讨论(0)
  • 2020-12-30 02:50

    You can try using freezetime module.

    from yourfile import get_report_month_key
    from freezegun import freeze_time
    import unittest
    
    class TestCase(unittest.TestCase):
    
        @freeze_time('2017-05-01')
        def get_report_month_key_test():
           get_report_month_key().should.equal('201705')
    
    0 讨论(0)
  • 2020-12-30 02:52

    If your code is in another file you need to patch where the import happens (lets call your file file1.py):

    from file1 import get_report_month_key
    import mock
    
    @mock.patch("get_report_month_key.datetime.utcnow")
    def test_get_report_month_key(mock_utcnow):
        mock_utcnow.return_value = "your value"
        assert get_report_month_key() == "your expected value"
    

    Of course, I would wrap it with unittest framework.

    0 讨论(0)
提交回复
热议问题