无法使用Mockito / JMockit / Deencapsulation模拟或绕过静态方法

时间:2018-11-26 13:49:21

标签: spring-boot junit mockito junit4 jmockit

我正在尝试使用Mockito添加测试用例。但是在此方法内部,有一个对静态方法的调用,该方法根据逻辑返回null,因为它是静态方法,所以我无法模拟它的行为。我需要模拟它或以某种方式绕过它。

我在堆栈溢出中经历了类似的链接,但是无法解决我的问题,可能是因为几年前有人提出了一些疑问,建议的解决方案可能不适合我的问题。

我正在分享下面的代码。请分享您的想法。

BrandServiceImpl.java

package com.thewatchcompany.modelsdb.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.thewatchcompany.modelsdb.domain.core.Brand;
import com.thewatchcompany.modelsdb.repository.BrandRepository;

@Service("brandService")
public class BrandServiceImpl extends AbstractResourceService<Brand, 
BrandRepository> implements BrandService {

private static final Logger LOGGER = 
LoggerFactory.getLogger(BrandServiceImpl.class);

   @Autowired
   public BrandServiceImpl(BrandRepository brandRepository) {
       super(brandRepository);
       LOGGER.info(" brandRepository : {} ", brandRepository);
   }

   protected Class<Brand> getResourceType() {
       return Brand.class;
   }
}

AbstractResourceService.java

请注意,该文件中的测试用例失败,我们在其中使用setCreator()设置Creator,并从名为ModelsDBUtil.java的实用工具类中调用静态方法getRequestor()。

package com.thewatchcompany.modelsdb.service;

import static com.thewatchcompany.modelsdb.ModelsDbUtil.getRequestor;

import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.repository.MongoRepository;

import com.thewatchcompany.modelsdb.domain.SearchRequest;
import com.thewatchcompany.modelsdb.domain.core.AbstractResource;
import com.thewatchcompany.modelsdb.domain.core.Resource;
import com.thewatchcompany.modelsdb.exception.ResourceNotFoundException;
import com.thewatchcompany.modelsdb.repository.MongoCustomRepository;

public abstract class AbstractResourceService<T extends Resource, R extends 
MongoRepository<T, String> & MongoCustomRepository<T>>
        implements ResourceService<T> {

    private static final Logger LOGGER = 
    LoggerFactory.getLogger(AbstractResourceService.class);

    private final R repository;

    public AbstractResourceService(R newRepository) {
        this.repository = newRepository;
    }

    protected abstract Class<T> getResourceType();

    protected void validateAdd(T resource) {

    }   

    /** {@inheritDoc} */   
    public T add(T resource) {

        LOGGER.info("Adding resource : {}", resource.getClass().getSimpleName());

        validateAdd(resource);

        if (resource instanceof AbstractResource) {
        ((AbstractResource) resource).setCreationInstant(System.currentTimeMillis()).setCreator(getRequestor());
        } else {
            LOGGER.warn("Invalid resource type: {}", resource.getClass().getName());
        }

        return repository.save(resource);
    }
}

ModelsDbUtil.java

package com.thewatchcompany.modelsdb;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import com.thewatchcompany.modelsdb.domain.core.Resource;
import com.thewatchcompany.modelsdb.exception.ResourceNotFoundException;
import com.thewatchcompany.modelsdb.service.ResourceService;

public final class ModelsDbUtil {

    private ModelsDbUtil() {
        // Prohibit instantiation
    }

    public static String getRequestor() {
        final Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            return ((UserDetails) principal).getUsername();
        }
        return null;
    }
}

最后,测试类:

package com.thewatchcompany.modelsdb.service;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import com.thewatchcompany.modelsdb.ModelsDbUtil;
import com.thewatchcompany.modelsdb.domain.core.Brand;
import com.thewatchcompany.modelsdb.repository.BrandRepository;
import mockit.MockUp;

// @RunWith(PowerMockRunner.class)
// @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
// @PrepareForTest(ModelsDbUtil.class)
// @RunWith(JMockit.class)
@RunWith(SpringRunner.class)
@SpringBootTest
public class BrandServiceTest {

    @MockBean
    private BrandRepository brandRepository;

    @Autowired
    private BrandService brandService;

    private Brand brand;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        brand = new Brand();
        brand.setId("001");
        brand.setName("Panerai");
        brand.setDescription("Panerai watches");
        brand.setActive(true);
    }

    @Test
    public void testAdd() {

        when(brandRepository.save(ArgumentMatchers.any(Brand.class)))
             .thenReturn(brand);

        // final ModelsDbUtil handler2 = spy(ModelsDbUtil.class);
        // doReturn("").when(handler2).getRequestor();

       // doReturn("").when(modelsDBUtil.getRequestor());
       // when(ModelsDbUtil.getRequestor()).thenReturn("");

       // final AbstractResource handler = spy(AbstractResource.class);
       // Mockito.ignoreStubs(handler.setCreator(ArgumentMatchers.anyString()));        

        // new MockUp<ModelsDbUtil>() {
        //            @mockit.Mock
        //            String getRequestor() {
        //                return "dssd";
        //            }
        //        };

        //final String user = Deencapsulation.invoke(ModelsDbUtil.class, "getRequestor"); //Null-pointer exception
        //assertEquals("user", user); 

        final Brand savedBrand = brandService.add(brand);
        assertEquals(savedBrand, brand);
    }
}

0 个答案:

没有答案