Spring embedded ldap server in unit tests

2020-07-05 05:53发布

问题:

I am currently trying to use an embedded ldap server for unit tests.

In Spring Security, you can quickly define an embedded ldap server for testing with the tag with some sample data loaded from the specified ldif.

I will be using Spring Ldap to perform ldap operations, and thinking of testing the usual CRUD features of my User service object.

Is there, however, a way to ensure that the entries in the embedded server to be in the same consistent state (sort of like a delete all and reload the ldif entries) for each test I am running?

I thought of the following: 1) Indicate that the method dirties the context, and force a recreation of the embedded ldap server, which sounds painful as it would have to restart the server for every method 2) Create the test entries in a test organization, such that I can unbind them and simply load in the ldif file again there.

I prefer 2, but it seems like the Spring LDAP has no good helpers to load and send across the content of a ldif file.

Any suggestions on how you perform ldap testing with an embedded ldap server of spring, or of the two possible solutions I mention?

Thanks

回答1:

I may be off-track here, but if you're not testing the LDAP integration itself, you could Mock out the LDAP connection with a Mock object that always returns the values you expect so that your other Unit Tests can complete.

If you're testing the LDAP connection then you're really doing an integration test. In which case it's probably best to connect to a real LDAP implementation.



回答2:

Doesn't Spring LDAP provide transactional control around LDAP operations? If so, why not use Spring test framework with its auto-rollback capability?

I also know of a JDBC-LDAP bridge driver that wraps an LDAP repository, presenting it as a relational database. I've used iBatis to connect to this (I've written this up at http://lokibear.blogspot.com, see articles from July). I've not yet tried applying transactional control, but the website for the driver mentions the ability to ignore transactions (which means you can also not ignore them...right?).

Like I say, I haven't tried this yet; but, if this provides transactions around LDAP, then you can again use the Spring test framework to get auto-rollback in place. I've put out a quick cheatsheet around that framework - see the September posts at my blog.

Sorry, I might be missing your goal here; but perhaps these suggestions are useful. Good luck!



回答3:

You may or may not know that the embedded LDAP functionality is not provided by Spring LDAP itself, but Apache Directory Server. Unfortunately, the LDIF loader in Apache DS (as wired by Spring, anyway) has very poor error handling and reporting capability, and as such is probably not going to behave as you really want for a unit test. Your best bet if you really want to start from a clean slate each time is to take the lead of the Spring Security LDAP unit tests and reinitialize Apache DS every time, with a clean LDIF file load.

Alternatively, you could eschew LDIF altogether and construct your own unit test wrapper that verifies the pre- and post-conditions of the data prior to your unit tests running. This would be more work, but ultimately may work out better for you.



回答4:

Works fine for me:

@Inject
private ApplicationContext applicationContext;

@Before
public void reloadLdapDirectory() throws NamingException, IOException{
    ApacheDSContainer apacheDSContainer = (ApacheDSContainer) applicationContext.getBean(BeanIds.EMBEDDED_APACHE_DS);
    LdapTestUtils.clearSubContexts(contextSource, DistinguishedName.EMPTY_PATH);

    ClassPathResource classPathResource = new ClassPathResource("ldap.ldif");

    File tempFile = File.createTempFile("spring_ldap_test", ".ldif");
    try {
        InputStream inputStream = classPathResource.getInputStream();
        IOUtils.copy(inputStream, new FileOutputStream(tempFile));
        LdifFileLoader fileLoader = new LdifFileLoader(apacheDSContainer.getService().getAdminSession(), tempFile.getAbsolutePath());
        fileLoader.execute();
    }
    finally {
        try {
            tempFile.delete();
        }
        catch (Exception e) {
            // Ignore this
        }
    }
}

I asked something similar and got an answer from Luke Taylor: Integration tests with spring-security and ldap