From 00f20ab1d481342b7297df14f5ff42a31c185469 Mon Sep 17 00:00:00 2001 From: chenke Date: Thu, 6 Jun 2019 17:14:26 +0800 Subject: [PATCH] Fix property access in test_global_preference* tests In Python, when we use @property, the method will be decorated by property. When we call method self.strategy.datasource_backend()[1], Actually it did two things: 1. call self.strategy.datasource_backend() 2. according to the method's return value[2], call self._datasource_backend() [1]. https://github.com/openstack/watcher/blob/bd8636f3f/watcher/tests/decision_engine/strategy/strategies/test_base.py#L87 [2]. https://github.com/openstack/watcher/blob/bd8636f3f/watcher/decision_engine/strategy/strategies/base.py#L368 But in this part, we just want it to perform the first step. So we have to use self.strategy.datasource_backend instead of self.strategy.datasource_backend() The reason why the unittest does not report an error is because the returned value is a mock object, and the second step is executed without error, for example: python -m unittest watcher.tests.decision_engine.strategy.strategies.test_base (Pdb) x=self.strategy.datasource_backend (Pdb) type(x) (Pdb) x (Pdb) x() (Pdb) self.strategy.datasource_backend() To make the tests more robust, the underlying backend function is mocked to be not callable. Co-Authored-By: Matt Riedemann Change-Id: I3305d9afe8ed79e1dc3affe02ba067ac06cece42 --- .../strategy/strategies/test_base.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/watcher/tests/decision_engine/strategy/strategies/test_base.py b/watcher/tests/decision_engine/strategy/strategies/test_base.py index b6e0bfe2d..802408243 100644 --- a/watcher/tests/decision_engine/strategy/strategies/test_base.py +++ b/watcher/tests/decision_engine/strategy/strategies/test_base.py @@ -66,9 +66,13 @@ class TestBaseStrategyDatasource(TestBaseStrategy): m_conf.watcher_datasources.datasources = \ ['gnocchi', 'monasca', 'ceilometer'] + # Make sure we access the property and not the underlying function. + m_manager.return_value.get_backend.return_value = \ + mock.NonCallableMock() + # Access the property so that the configuration is read in order to # get the correct datasource - self.strategy.datasource_backend() + self.strategy.datasource_backend m_manager.assert_called_once_with( config=m_conf.watcher_datasources, osc=None) @@ -82,9 +86,13 @@ class TestBaseStrategyDatasource(TestBaseStrategy): m_conf.watcher_datasources.datasources = \ ['ceilometer', 'monasca', 'gnocchi'] + # Make sure we access the property and not the underlying function. + m_manager.return_value.get_backend.return_value = \ + mock.NonCallableMock() + # Access the property so that the configuration is read in order to # get the correct datasource - self.strategy.datasource_backend() + self.strategy.datasource_backend m_manager.assert_called_once_with( config=m_conf.watcher_datasources, osc=None) @@ -105,7 +113,7 @@ class TestBaseStrategyDatasource(TestBaseStrategy): # Access the property so that the configuration is read in order to # get the correct datasource - self.strategy.datasource_backend() + self.strategy.datasource_backend m_manager.assert_called_once_with( config=datasources, osc=None)