[389-devel] Proof of concept: mocking DS in lib389

thierry bordaz tbordaz at redhat.com
Tue Oct 29 14:30:26 UTC 2013


On 10/29/2013 02:18 PM, Jan Rusnacko wrote:
> Hello Thierry,
>
> I am not rewriting ldapadd,...  methods of "real" DS class, I am in fact
> creating MockDS class with custom ldapadd,... methods, _just_ like you suggest :)
>
> Furthermore, you can view it as a subclass of "real_ds" - even though it is not
> a proper Python subclass, it inherits all functions from repl module just like
> "real_ds" would (again through ModuleProxy mechanism). So, methods that are
> defined in repl are the same for "real_ds" class and for MockDS class, but
> ldap.. methods are different. So, basically exactly what you suggest :)

Hi Jan,

    Sorry my question was not clear. For example an other approach could be

        Class DSInstance (object):
             def __init__(self):
                 ...

             def ldapadd_r(self, input):
                 # real call to pythonldap.add_s

        Class MockDSInstance(DSInstance):
             def __init__(self):
                 ...

             def ldapadd_r(self, input):
                 input = input.strip()
                 entry = dict(e.strip().split(': ') for e in
        input.split('\n'))
                 self.dit[entry['dn']] = entry



    My understanding is that both approach would allow us to call
    inherited methods, just ldap method are different.
    What are the advantages of the approach you described compare to the
    one above ?

best regards
thierry
>
> Code of the whole class along with all methods is in file
> tests/test_dsmodules/conftest.py line 7.
>
> Thank you,
> Jan
>
> On 10/28/2013 12:02 PM, thierry bordaz wrote:
>> Hi Jan,
>>
>>      That is very impressive POC, far above my skill in python. Thanks for
>>      sharing this.
>>      I have a novice question.
>>      This implementation overwrites the basic ldapadd,ldapsearch... function of
>>      the "real" DS.
>>      An other approach is to write a 'mock_ds' class being a subclass of
>>      'real_ds' and to overwrite the ldapadd,ldapsearch in mock_ds class (to store
>>      data into a dict). What would be the advantages of your approach ?
>>
>> best regards
>> thierry
>>
>> On 10/25/2013 09:36 PM, Jan Rusnacko wrote:
>>> Hello Roberto and Thierry,
>>>
>>> as I promised, I am sending you a proof-of-concept code that demonstrates, how
>>> we can mock DS in unit tests for library function (see attachment). You can run
>>> tests just by executing py.test in tests directory.
>>>
>>> Only 3 files are of interest here:
>>>
>>> lib389/dsmodules/repl.py - this is a Python module with functions - they expect
>>> DS instance as the first argument. Since they are functions, not methods, I can
>>> just mock DS and pass that fake one as the first argument to them in unit tests.
>>>
>>> tests/test_dsmodules/conftest.py - this file contains definition of mock DS
>>> class along with py.test fixture, that returns it.
>>>
>>> tests/test_dsmodules/test_repl.py - this contains unit tests for functions from
>>> repl.py.
>>>
>>> What I do is quite simple - I override ldapadd, ldapdelete .. methods of mock DS
>>> class, so that instead of sending command to real DS instance, they just store
>>> the data in 'dit' dictionary (which represents content stored in DS). This way,
>>> I can check that when I call e.g. function enable_changelog(..), in the end DS
>>> will have correct changelog entry.
>>>
>>> To put it very bluntly - enable_changelog(..) function just adds correct
>>> changelog entry to whatever is passed to it as the first argument. In unit
>>> tests, it is mock DS, otherwise it would be real DS class that sends real ldap
>>> commands to real DS instance behind.
>>>
>>> Now I can successfully test that enable_changelog really works, without going
>>> into trouble defining DSInstance or ldap calls at all. Also, I believe this
>>> approach would work for 95% of all functions in lib389. Another benefit is that
>>> unit tests are much faster, than on real DS instance.
>>>
>>> Sidenote: even though everything is defined in separate namespace of 'repl'
>>> module as function, in runtime they can be used as normal methods of class
>>> DSInstance. That is handled by DSModuleProxy. We already went through this, but
>>> not with Roberto.
>>>
>>> Hopefully, now with some code in our hands, we will be able to understand each
>>> other on this 'mocking' issue and come to conclusions more quickly.
>>>
>>> Let me know what you think.
>>>
>>> Thank you,
>>> Jan

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.fedoraproject.org/pipermail/389-devel/attachments/20131029/e88864a3/attachment.html>


More information about the 389-devel mailing list