1、在涉及到有HTTP發送請求的測試,而所要訪問的接口又沒有準備好,就需要用到 mockServer:
當一個測試類中有多個測試用例的時候,必須使用static. 測試發現,測試類中不使用static的字段,每個測試用例執行的時候都會創建新的對象,會出現端口創建異常的情況,即使使用了mockServer.stop,當GET,POST都測試的時候,也會出現返回爲空的情況(端口衝突)
// pom文件
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>3.10.1</version>
</dependency>
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.model.Header;
import org.mockserver.model.HttpRequest;
// 模擬的訪問地址爲:localhost:1002(端口自己指定)
ClientAndServer mockServer = startClientAndServer(1002);
// 防止有緩存的設置
mockServer.reset();
// 設置期望的返回結果
String expected = "{\"success\":false,\"message\":\"success\"}";
// 請求:請求方式,請求地址(可加其他參數)
HttpRequest request = request().withMethod("POST").withPath("/test");
Header header = new Header("Content-Type", "application/json;charset=utf-8");
mockServer.when(request).respond(response()
.withStatusCode(200) // 表示響應成功
.withBody(expected) // 響應體爲期望值
.withHeader(header)); // 響應數據的格式及編碼
訪問到該地址時返回的結果是預期設定的值。
2、某些類在調用某個方法時,想要讓其返回想要的數據,可以用 mock:
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
eg:
XxService abc = mock(XxService.class);
// 1、想讓該實例調用方法時返回想要的結果
UserService userService = mock(UserServiceImpl.class);
when(userService.getCurUser()).thenReturn(user);
///2、想讓調用方法時拋出指定異常
RedisUtil util = mock(RedisUtil.class);
doThrow(Exception.class).when(util).publish(anyString(), anyString());
<!— any()表示調用方法的入參可以填任意值 —>
然後通過反射,將mock出來的對象設置到指定的位置,當執行到指定位置的時候,對象調用所用的就是mock出來的對象,調用的返回結果就是thenReturn的返回結果。
Class<CustomerServiceImpl> cla = CustomerServiceImpl.class;
Constructor<CustomerServiceImpl> cfon = cla.getConstructor();
CustomerServiceImpl obj = cfon.newInstance();
//
Field field = cla.getDeclaredField("redisUtil");
field.setAccessible(true);
field.set(obj, util);
// 通過反射調用方法
Method method = cla.getMethod("setCustomerExtraData", Customer.class);
boolean result = (boolean) method.invoke(obj, customer);
// 保證mock的對象重新設置回原來的對象,不然後繼操作會受到影響
reset(userService);
注意:如果所測試的方法中有其他自動注入的對象,也要在測試類裏進行自動注入。然後通過反射給他們設置進去,不然會讀取不到!
一些難以覆蓋的地方都可以通過反射來進行測試。
3、測試Dao層的時候,可以用到DBUnit,主要用於測試前的數據準備,以及測試後期望值對比:
// pom文件引入
<dependency>
<groupId>com.github.springtestdbunit</groupId>
<artifactId>spring-test-dbunit</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.3</version>
<scope>test</scope>
</dependency>
// 類的監聽
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DbUnitConfiguration(dataSetLoader= XmlDataSetLoader.class)
準備數據 @DatabaseSetup(type = DatabaseOperation.INSERT,value = "classpath:/data/consumer.xml") 將需用用到的數據添加到data下consumer.xml文件中,數據格式爲:
// 準備數據
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<tb_consumer id="[NULL]" name="Junit_consumer" type="2" address="Junit_address"
contact_number="110" state="1" create_time="[NOW]" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer id="[UUID]" name="Junit_consumer2" type="2" address="[NULL]"
contact_number="120" state="1" create_time="[NOW]" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer id="[UUID]" name="Junit_consumer2" type="[NULL]" address="Junit_address"
contact_number="130" state="1" create_time="[NOW]" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer id="[UUID]" name="Junit_consumer2" type="2" address="Junit_address"
contact_number="140" state="1" create_time="[NOW]" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer id="[UUID]" name="Junit_consumer2" type="2" address="Junit_address"
contact_number="150" state="1" create_time="[NOW]" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
</dataset>
dataset節點下子節點爲表名。可以寫入多張表,屬性爲表的字段,帶[]字段爲佔位符[UUID] 爲32位uuid,[NOW] 爲當前時間,[NULL] 爲null.
// 期望
@ExpectedDatabase(table = "tb_consumer",query="select * from tb_consumer where name like 'Junit%'", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED , value = "data/consumerExpect.xml")
期望文件 query爲期望文件與數據庫中哪些數據對比,如果不填將與數據庫中所有數據對比, table 爲表名,value爲期望文件,填寫期望數據,當assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED 時,沒填的字段將不會對比
// 期望數據
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<tb_consumer name="Junit_consumer2" type="2" address="[NULL]"
contact_number="120" state="1" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer name="Junit_consumer" type="2" address="Junit_address"
contact_number="110" state="1" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer name="Junit_consumer2" type="[NULL]" address="Junit_address"
contact_number="130" state="1" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer name="Junit_consumer2" type="2" address="Junit_address"
contact_number="140" state="1" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
<tb_consumer name="Junit_consumer2" type="2" address="Junit_address"
contact_number="150" state="1" create_user_id="c0dc744d3aee11e892cb0025901bf22a" />
</dataset>
@Transactional 事物標籤,當方法執行完後,數據庫中的數據將回滾,不會影響原有數據
@SpringBootTest
@RunWith(SpringJUnit4Cla***unner.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DbUnitConfiguration(dataSetLoader= XmlDataSetLoader.class)
public class ConsumerMapperDbUnitTest {
@Autowired
private ConsumerMapper consumerMapper;
@Test
@Transactional(rollbackFor = Exception.class)
@DatabaseSetup(type = DatabaseOperation.INSERT, value = "data/consumer.xml")
@ExpectedDatabase(table = "tb_consumer", query = "select * from tb_consumer where name like 'Junit%'", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED,
value = "data/consumerExpect.xml")
public void testInsert() {
List<Consumer> list = consumerMapper.selectAll();
assertNotEquals(list.size(), 0);
}
}