2011-12-25 135 views
2

调用方法我有以下里面的类和方法的Mockito:内部方法

public class A extends B implements C{ 


public void validateTicketGrantingTicket(final TicketGrantingTicket ticketGrantingTicket) throws InvalidTicketException { 

    if (ticketGrantingTicket != null) 
    { 
     if (!ticketGrantingTicket.getHostDomain().equalsIgnoreCase(getServerName())) 
     { 
      throw new InvalidTicketException(); 
     } 
    } 
} 


public String getServerName() 
{ 
    String serverName = ""; 
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 

    if (request != null) 
    { 
     serverName = request.getServerName().toLowerCase(); 
    } 

    return serverName; 
} 
} 

现在我写ATEST类和嘲讽类A.

public class ATest { 
private A a; 

@Before 
public void init(){ 

    A = mock(A.class); 

    when(A.getServerName()).thenReturn("phoenix.edu.abc");  
} 


@Test 
public void validateTicketGrantingTicketTest() throws InvalidTicketException{ 
    a = new A(); 
    ticketGrantingTicket = new 
    TicketGrantingTicketImpl("test",testUtils.getAuthentication(), new 
    NeverExpiresExpirationPolicy()); 

    a.validateTicketGrantingTicket(ticketGrantingTicket); 
} 

模仿对象是给我的空指针异常为getServerName()方法而不是字符串“phoenix.edu.abc”

回答

7

通过在您的测试方法中调用a = new A();,您创建一个新的A实例并引用模拟的A inst在init()方法中创建的ance将会丢失。因此,A的getServerName()方法的“真正”实现将被调用,而不是您嘲笑的方法。

你有的另一个问题是你试图同时模拟和测试同一个类。一方面你正在测试validateTicketGrantingTicket(),但同时你正在嘲笑getServerName()。你可以通过使用spy()而不是mock()来解决此问题,但最好将代码重构为两个独立的类。

+0

呀喜欢2类重构,最好是有diferent responsabilities班,早于具有多个reponsabilities类,(它会导致不可维护的代码) – Brice 2012-01-01 11:12:29

0

我想这不是一个好主意,将方法getServerName移动到一个不同的类,以便它可以在别处重新使用?这将使测试这种情况变得很容易。

正如matsev所说,你也试图模拟被测试的类,这不是正确的做法。正如他所指出的那样,这可以在例外情况下使用,使用spy()。即使mockito在其后续版本中引入了此功能,但强烈建议其用户限制使用spy()

如果您将方法移动到新类,您可以轻松地模拟其他类并返回所需的值。

public class A extends B implements C{ 
private AUtil util; 

public void validateTicketGrantingTicket(final TicketGrantingTicket ticketGrantingTicket) throws InvalidTicketException { 

    if (ticketGrantingTicket != null) 
    { 
     String serverName = util.getServerName() 
     if (!ticketGrantingTicket.getHostDomain().equalsIgnoreCase(serverName)) 
     { 
      throw new InvalidTicketException(); 
     } 
    } 
} 
} 


public class AUtil { 
public String getServerName() 
{ 
    String serverName = ""; 
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 

    if (request != null) 
    { 
     serverName = request.getServerName().toLowerCase(); 
    } 

    return serverName; 
} 
} 

现在,这也算是一个好的设计,如果我们把所有的实用功能于共同类型从一个像所有的类可以重新使用它们。它现在有一个单独的关注和更好的可测试性。你可以轻松地嘲笑这种方法,而无需间谍。

public class ATest { 

//cut provides a uniform naming convention-Class Under Test 
private AUtil cut; 

//Mock can now be created using annotations in Mockito 
@Mock 
AUtil mock; 

@Test 
public void validateTicketGrantingTicketTest() throws InvalidTicketException{ 

    cut = new A(); 

    ticketGrantingTicket = new 
    TicketGrantingTicketImpl("test",testUtils.getAuthentication(), new 
    NeverExpiresExpirationPolicy()); 

    when(mock.getServerName()).thenReturn("phoenix.edu.abc"); 

    a.validateTicketGrantingTicket(ticketGrantingTicket); 
} 
} 
+0

的Mockito不支持静态方法。 – brucenan 2013-02-28 02:46:59