Java 如何为单元测试创建假数据和数据对象?

Java 如何为单元测试创建假数据和数据对象?,java,junit,junit5,Java,Junit,Junit5,我有一个实现缓存的类,我想为它编写一个JUnit测试。 该类实现并与以下方法交互: public void insert(Object key, Object value); public Object getFromCache(Object key); 基本实现是单例。 我正在编写一个JUnit测试,但我不知道如何正确地创建一个包含数据的虚拟缓存,以便用于测试。 现在我正在做: @Test public void myTest() { MyCache cache = MyCa

我有一个实现缓存的类,我想为它编写一个JUnit测试。
该类实现并与以下方法交互:

public void insert(Object key, Object value);  
public Object getFromCache(Object key);
基本实现是单例。
我正在编写一个JUnit测试,但我不知道如何正确地创建一个包含数据的虚拟缓存,以便用于测试。
现在我正在做:

@Test
public void myTest() {  
    MyCache cache = MyCache.getInstance();  
    populateWithData(cache);  
    //test cache  
    asserEquals etc  
}  

如何避免使用
getInstance()
而不在每个测试中填充?

在每个测试之前“重置”单例。可以找到更多细节

例如:

@Before
public void resetMyCacheSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
   Field instance = MyCache.class.getDeclaredField("instance");
   instance.setAccessible(true);
   instance.set(null, null);
}

每次测试前“重置”单例。可以找到更多细节

例如:

@Before
public void resetMyCacheSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
   Field instance = MyCache.class.getDeclaredField("instance");
   instance.setAccessible(true);
   instance.set(null, null);
}

显然我有点误解了你的问题

正如其他两个答案所述,如果您想要有一个特定的缓存,在运行每个测试用例时可以从中读取,那么您可以使用一个´@before`方法,该方法初始化要在测试用例中使用的对象。定义的每个'@before'方法在调用每个测试用例之前被调用。这意味着您可以编写代码一次而不是多次实例化对象

注意,如果您想在测试用例中做一些不同的事情,请考虑在上面添加自定义,而不是在方法之前编辑<代码> @,因为这将影响所有的测试用例。 为了清楚起见,我将包括一些代码:

MyCache cache = null;

@before
public void initCache(){
    cache = MyCache.getInstance();  
    populateWithData(cache);  
}

// ... rest of your program here ...
原始答案

如果您想对更复杂的对象进行更奇特的测试,可以使用此选项。这仍然可以与‘@before’注释结合使用

你可以试试

这基本上是一个模拟函数或类的框架,您对完全实现它不感兴趣,尤其是对于测试

以下是使用模拟关闭列表的示例:

import static org.mockito.Mockito.*;

// mock creation
List mockedList = mock(List.class);

// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();

// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();

// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);

// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");

// the following prints "first"
System.out.println(mockedList.get(0));

// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));

您基本上可以告诉mockito您希望对对象调用哪些函数,以及您希望结果是什么。。。多才多艺。我希望它能满足你的需要。

显然我有点误解了你的问题

正如其他两个答案所述,如果您想要有一个特定的缓存,在运行每个测试用例时可以从中读取,那么您可以使用一个´@before`方法,该方法初始化要在测试用例中使用的对象。定义的每个'@before'方法在调用每个测试用例之前被调用。这意味着您可以编写代码一次而不是多次实例化对象

注意,如果您想在测试用例中做一些不同的事情,请考虑在上面添加自定义,而不是在方法之前编辑<代码> @,因为这将影响所有的测试用例。 为了清楚起见,我将包括一些代码:

MyCache cache = null;

@before
public void initCache(){
    cache = MyCache.getInstance();  
    populateWithData(cache);  
}

// ... rest of your program here ...
原始答案

如果您想对更复杂的对象进行更奇特的测试,可以使用此选项。这仍然可以与‘@before’注释结合使用

你可以试试

这基本上是一个模拟函数或类的框架,您对完全实现它不感兴趣,尤其是对于测试

以下是使用模拟关闭列表的示例:

import static org.mockito.Mockito.*;

// mock creation
List mockedList = mock(List.class);

// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();

// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();

// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);

// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");

// the following prints "first"
System.out.println(mockedList.get(0));

// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));

您基本上可以告诉mockito您希望对对象调用哪些函数,以及您希望结果是什么。。。多才多艺。我希望它能满足您的需要。

您可以使用@BeforeClass注释来完成一些常见的、可能是计算成本高昂的事情

这将在所有测试用例之前只运行一次

@BeforeClass
public static void myTest() {  
    MyCache cache = MyCache.getInstance();  
    populateWithData(cache);  
    //test cache  
    asserEquals etc  
} 
另外,由于@BeforeClass只能与静态方法一起使用,populateWithData()也需要是静态的。由于populateWithData()方法是静态的,所以它内部使用的变量也必须是静态的


您还可以选中@AfterClass来清除/重置一些数据/资源

您可以使用@BeforeClass注释来执行一些常见的操作,这些操作可能需要花费大量的计算时间

这将在所有测试用例之前只运行一次

@BeforeClass
public static void myTest() {  
    MyCache cache = MyCache.getInstance();  
    populateWithData(cache);  
    //test cache  
    asserEquals etc  
} 
另外,由于@BeforeClass只能与静态方法一起使用,populateWithData()也需要是静态的。由于populateWithData()方法是静态的,所以它内部使用的变量也必须是静态的


您还可以选中@AfterClass来清除/重置一些数据/资源

单例实现接口的事实是否有助于实现不同的接口?经典单例将实例值硬编码到类内部。因此,使用或不使用接口对您没有帮助。如果您想要模拟所实现的服务,该接口将帮助您。但在这里,你不想模仿它,你想测试它。单例实现接口的事实是否有助于实现不同的功能?经典单例将实例值硬编码到类内部。因此,使用或不使用接口对您没有帮助。如果您想要模拟所实现的服务,该接口将帮助您。但是这里你不想模拟它,你想测试它。但是我如何从
@BeforeClass
中获取测试缓存的实例呢?我已经根据你提供的示例代码编辑了我的答案,包括代码片段。只需注意,JUnit 5等价的注释是
@BeforeAll
@AfterAll
(问题已标记为junit5)。但是您将
@BeforeClass
标记为将运行测试的方法?我认为注释是用于初始化第二个方法使用的数据的其他方法。我的意图是显示该方法独立于任何测试用例,并且在特定类中,它只在所有测试用例之前运行一次。但是如何uld我是否可以从
@BeforeClass
获取测试缓存的实例?我已经根据您提供的示例代码编辑了我的答案,以包含代码片段。请注意,JUnit 5等效注释是
@Be