如何模拟超级引用(在超级类上)?

问题描述 投票:0回答:3

有时,当我编写单元测试时,我应该模拟对超类的引用。

我读过这个问题: 问题

这个答案 用 DI 回答建议重构代码。但我做不到

如果超类方法足够大,则

这个答案另一个答案不适合。就我而言,我有非常大的代码。是的,我知道这违反了 SOLID OOD 原则,但我应该编写测试。我没有足够的时间进行重构。

这个问题是4年前提出的!

目前Mockito或Powermock可以解决这个问题吗?

更新

代码示例:

class BaseService {  
    public void save() {
      // a lot of code here! I cannot change this code.
    }  
}

public Childservice extends BaseService {  
    public void save(){  
        //logic for testing
        super.save();
       //logic for testing
    }  
} 

更新2

public class Parent {
    public int save() {
         return 99;
    }   
}

public class Child extends Parent {
    public int save() {
        int i = super.save();
        return i*2;
    }
}

并测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Parent.class)
public class ParentTest {
    @Test
    public void testSave() {       
        PowerMockito.suppress(PowerMockito.methodsDeclaredIn(Parent.class));        
        System.out.println(new Child().save());
    }
}

输出:198

java unit-testing mocking super powermock
3个回答
3
投票

使用 Powermock,您可以替换或抑制方法,因此可以更改

BaseService.save()
完成的操作。您还可以创建不执行任何抑制操作的方法。您甚至可以抑制静态初始化块。

请阅读Powermock 作者的博客文章。请参阅“更换”一章。

更新:

抑制似乎对我有用,但替换不行。见下图: enter image description here


0
投票

这实际上并不是在嘲笑超级引用,但我认为这对于想要测试双亲方法的人很有帮助。

在我的例子中,我创建了一个新方法来包装超类的方法并进行测试替身。因为当我实现 oAuth2 客户端时,我需要来自超类方法的结果。我希望这个答案对需要使用超类方法结果的人有所帮助。

被测系统

  • 创建一个
    loadUserFromParent
    方法来包装超类函数
package action.in.blog.service;

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DefaultOAuth2UserServiceDelegator extends DefaultOAuth2UserService {

    private final List<CustomOAuth2UserService> oAuth2UserServices;


    public DefaultOAuth2UserServiceDelegator(List<CustomOAuth2UserService> oAuth2UserServices) {
        this.oAuth2UserServices = oAuth2UserServices;
    }

    public OAuth2User loadUserFromParent(OAuth2UserRequest userRequest) {
        return super.loadUser(userRequest);
    }

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        for (var oauth2Service : oAuth2UserServices) {
            if (!oauth2Service.supports(userRequest)) {
                continue;
            }
            var oauthUser = loadUserFromParent(userRequest);
            return oauth2Service.createOrLoadUser(oauthUser);
        }
        throw new RuntimeException("Not found user service");
    }
}

测试

  • 让 SUT 成为间谍
  • 使用
    doReturn(expectedValue).when(testDouble).method(params)
package action.in.blog.service;

import action.in.blog.domain.CustomAuthentication;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

class DefaultOAuth2UserServiceDelegatorTest {

    CustomOAuth2UserService googleUserService;
    CustomOAuth2UserService facebookUserService;
    DefaultOAuth2UserServiceDelegator sut;

    @BeforeEach
    void setUp() {
        googleUserService = mock(CustomOAuth2UserService.class);
        facebookUserService = mock(CustomOAuth2UserService.class);
        sut = spy(new DefaultOAuth2UserServiceDelegator(
                List.of(googleUserService, facebookUserService)
        ));
    }

    @Test
    void loadUser() {

        var authentication = new CustomAuthentication();
        var oauth2UserRequest = mock(OAuth2UserRequest.class);
        var oauth2User = new DefaultOAuth2User(Collections.emptyList(), Map.of("id", "junhyunny"), "id");
        // make a stub 
        doReturn(oauth2User).when(sut).loadUserFromParent(oauth2UserRequest);
        when(googleUserService.supports(oauth2UserRequest)).thenReturn(true);
        when(googleUserService.createOrLoadUser(oauth2User)).thenReturn(authentication);


        var result = sut.loadUser(oauth2UserRequest);


        assertEquals(result, authentication);
    }
}

-1
投票

这是不可能的;超类的全部要点在于它封装了上游状态和功能,并且类层次结构基于

extends
关系硬编码在子类中。

© www.soinside.com 2019 - 2024. All rights reserved.