Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring Test Code to Reduce Duplication of Mock Object Creation #14768

Open
gzhao9 opened this issue Mar 17, 2024 · 2 comments
Open

Refactoring Test Code to Reduce Duplication of Mock Object Creation #14768

gzhao9 opened this issue Mar 17, 2024 · 2 comments
Assignees
Labels
in: core An issue in spring-security-core type: enhancement A general enhancement

Comments

@gzhao9
Copy link

gzhao9 commented Mar 17, 2024

Dear Spring Security Developers,

I have been reviewing your test code and noticed an issue with repeated creation of mock objects in your tests. Here are four examples where this occurs:

Example 1

This example is found in ActiveDirectoryLdapAuthenticationProviderTests.
The repeated code fragment is as follows:

DirContext ctx = mock(DirContext.class);
given(ctx.getNameInNamespace()).willReturn("");

The issue with this code is that willReturn("") is unnecessary because Mockito defaults the return of String methods to "". This piece of code is used 18 times across 8 test cases.
Thus, I propose the following solution:

  1. Remove given(ctx.getNameInNamespace()).willReturn("");
  2. Move DirContext ctx = mock(DirContext.class); to @BeforeEach

This change reduces the code by 16 lines. I have created a Draft PR, and you can view the changes here.

Example 2

This code is repeated in 8 test cases across 3 test classes:

The repeated code is as follows:

SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
// other statements
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));

The creation and given content of SecurityContextHolderStrategy mocks are very similar each time, except for the return value.
My solution is to create a MockSecurityContextHolderStrategy function, which is called each time a mock is needed:

public class MockSecurityContextHolderStrategy {
    static SecurityContextHolderStrategy getmock(SecurityContextImpl securityContextImpl){

        SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
        given(strategy.getContext()).willReturn(securityContextImpl);
        return strategy;
    }
}

The code after calling it would look like this:

SecurityContextHolderStrategy strategy = MockSecurityContextHolderStrategy.getmock(new SecurityContextImpl(authentication));

I have created a Draft PR, and you can view the changes here.

Example 3

Similar to Example 2, I found repetition in the test class ConcurrentSessionFilterTests when creating mocks for SessionRegistry as follows:

SessionRegistry registry = mock(SessionRegistry.class);
SessionInformation information = new SessionInformation("user", "sessionId",
        new Date(System.currentTimeMillis() - 1000));
information.expireNow();
given(registry.getSessionInformation(anyString())).willReturn(information);

This repetition occurs in 6 test cases.

My solution is to create a mockSessionRegistry:

private SessionRegistry mockSessionRegistry(){
    SessionRegistry registry = mock(SessionRegistry.class);
    SessionInformation information = new SessionInformation("user", "sessionId",
            new Date(System.currentTimeMillis() - 1000));
    information.expireNow();
    given(registry.getSessionInformation(anyString())).willReturn(information);
    return registry;
}

To create a SessionRegistry, simply call as follows:

ConcurrentSessionFilter filter = new ConcurrentSessionFilter(mockSessionRegistry());

I have created

a Draft PR, and you can view the changes here.

Example 4

This repetition occurs in ExceptionTranslationFilterTests with the following code:

FilterChain fc = mock(FilterChain.class);
willThrow(new BadCredentialsException("")).given(fc)
    .doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));

This occurs in 8 different test cases, each returning a different Exception.

My solution is to create a method mockFilterChainWithException that takes different Exceptions as parameters:

private FilterChain mockFilterChainWithException(Object exception) throws ServletException, IOException {
    FilterChain fc = mock(FilterChain.class);
    willThrow((Throwable) exception).given(fc).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
    return fc;
}

To create a FilterChain mock, call it like this:

FilterChain fc = mockFilterChainWithException(new BadCredentialsException(""));

I have created a Draft PR, and you can view the changes here.


These are the four instances of repeated mock test code I found, along with my solutions for refactoring the test code. I believe these changes will

  1. reduce the LOC for each test case
  2. allowing tests to focus more on testing rather than on recreating objects.
  3. Most importantly, consolidating repetitive parts improves code maintainability.

Dear Spring Security developers, Do you like the solution proposed in the issue? I'm very much looking forward to your response, and I'm ready to start submitting PRs if you're interested. If you have any suggestions for improvements, I would greatly appreciate them.

@gzhao9 gzhao9 added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Mar 17, 2024
@jzheaux
Copy link
Contributor

jzheaux commented Apr 15, 2024

Thank you for your effort @gzhao9 to simplify these tests! To accelerate the review process, will you please instead open a PR to the main repository and I'll take a look?

@jzheaux jzheaux self-assigned this Apr 15, 2024
@jzheaux jzheaux added in: core An issue in spring-security-core and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 15, 2024
@gzhao9
Copy link
Author

gzhao9 commented Jun 18, 2024

Thank you for your effort @gzhao9 to simplify these tests! To accelerate the review process, will you please instead open a PR to the main repository and I'll take a look?

Thank you very much for your reply. I have submitted PR #15256. Please review it at your convenience.

I apologize for the delayed response as I've been occupied with some real-life matters over the past two months. I'm now back and actively engaged.

gzhao9 added a commit to gzhao9/spring-security that referenced this issue Sep 23, 2024
gzhao9 added a commit to gzhao9/spring-security that referenced this issue Sep 23, 2024
gzhao9 added a commit to gzhao9/spring-security that referenced this issue Sep 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core An issue in spring-security-core type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants