{"id":19838872,"url":"https://github.com/sayi/testpie","last_synced_at":"2026-04-16T14:03:24.318Z","repository":{"id":57718696,"uuid":"233587269","full_name":"Sayi/testpie","owner":"Sayi","description":":shallow_pan_of_food: 一种简单有效的单元测试方式","archived":false,"fork":false,"pushed_at":"2020-01-13T16:26:25.000Z","size":28,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-28T22:19:47.404Z","etag":null,"topics":["json","junit","mock","mockito","unittest","yaml"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sayi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-13T12:09:44.000Z","updated_at":"2020-03-23T12:21:59.000Z","dependencies_parsed_at":"2022-09-26T21:40:28.640Z","dependency_job_id":null,"html_url":"https://github.com/Sayi/testpie","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Sayi/testpie","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Ftestpie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Ftestpie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Ftestpie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Ftestpie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sayi","download_url":"https://codeload.github.com/Sayi/testpie/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Ftestpie/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278283492,"owners_count":25961310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","junit","mock","mockito","unittest","yaml"],"created_at":"2024-11-12T12:19:24.281Z","updated_at":"2025-10-04T07:43:09.935Z","avatar_url":"https://github.com/Sayi.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TestPie \n* :round_pushpin: **加载测试数据(JSON、YAML或其它格式)，by** `@PieData`\n* :clapper: **隔离Mock code和UnitTest code，by** `@MockPrimay` or `@MockProvider`\n\n## 依赖\n### Requirements\n* JUnit 5\n* Mockito(可选，如果需要使用mock功能)\n\n### Gradle\n```groovy\ntestImplementation \"com.deepoove:testpie:0.0.1\"\n```\n\n### Maven\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.deepoove\u003c/groupId\u003e\n  \u003cartifactId\u003etestpie\u003c/artifactId\u003e\n  \u003cversion\u003e0.0.1\u003c/version\u003e\n  \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n\n## `@PieData`：加载数据\n### 方式一、`Pie.initAnnotations(this)`\n**1). 准备测试数据user.json**\n\n```json\n{\n  \"phone\": 12306,\n  \"name\": \"Sayi\",\n  \"age\": 10\n}\n```\n**2). 加载数据**\n\n```java\n@PieData(value = \"/pie/user.json\")\nprivate User user;\n\npublic PieTest() {\n    Pie.initAnnotations(this);\n}\n\n@Test\npublic void testPieData() {\n    assertNotNull(user);\n}\n```\n\n### 方式二、`PieExtension`代替`Pie.initAnnotations`：\n\n```java\n@ExtendWith(PieExtension.class)\npublic class PieExtensionTest {\n\n  @PieData(value = \"/pie/user.json\")\n  private User user;\n\n  @Test\n  public void testPieData() {\n    assertNotNull(user);\n    assertEquals(user.getPhone(), 12306);\n  }\n}\n```\n\n### 扩展：使用`YamlConverter`加载yml数据\n```java\n@ExtendWith(PieExtension.class)\npublic class YamlConverterTest {\n\n  @PieData(value = \"/yaml/user.yml\", converter = YamlConverter.class)\n  private User user;\n\n  @Test\n  public void testPieDataByYaml() {\n    assertNotNull(user);\n    assertEquals(user.getPhone(), 12306);\n  }\n}\n```\n\n### 扩展：自定义数据格式转化器\n```java\npublic class GsonJsonConverter implements Converter {\n  @Override\n  public Object convert(String source, TypeContext context) {\n    Gson gson = new Gson();\n    return gson.fromJson(source, context.getType());\n  }\n}\n```\n\n## `@MockPrimay`：为某个对象提供mock\n一个对象的Mock功能可以被**快速构造**和**复用**，通过一个独立的类提供对象的所有Mock功能，这个类称为：该对象的Mock类，就像这样:\n\n```java\nSupplier\u003cUserService\u003e mock = new UserServiceMock();\nUserService userService = mock.get();\n```\n与这段代码等价的功能是TestPie提供了与Mockito集成的注解`@MockPrimay`来快速构造一个具有Mock功能的对象。\n\n### 方式一、使用`@MockPrimay`\n1). 创建一个单独的**对象Mock类**定义具体Mock功能\n\n```java\npublic class UserServiceMock implements Consumer\u003cUserService\u003e {\n\n  @PieData(\"/pie/list_user_.json\")\n  private List\u003cUser\u003e userList;\n\n  public UserServiceMock() {\n    // 加载数据\n    Pie.initAnnotations(this);\n  }\n\n  @Override\n  public void accept(UserService userService) {\n    // 处理Mock功能\n    given(userService.findAll()).willReturn(userList);\n    given(userService.delete(1590000)).willReturn(false);\n    given(userService.delete(1581111)).willReturn(true);\n  }\n}\n```\n\n2). 使用`@MockPrimay`快速初始化Mock对象\n\n```java\n@Mock(lenient = true)\n@MockPrimary(UserServiceMock.class)\nprivate UserService userService;\n\npublic PieMockitoTest() {\n    // first mockito\n    MockitoAnnotations.initMocks(this);\n    // the testpie\n    Pie.initAnnotations(this);\n}\n\n@Test\npublic void testPieData() {\n    assertFalse(userService.delete(1590000));\n    assertTrue(userService.delete(1581111));\n}\n```\n需要注意初始化的顺序，`@Mock`的顺序优先于`@MockPrimary`，即先使用Mockito初始化Mock对象，再使用TestPie指定该对象的Mock类。\n\n### 方式二、使用Junit5的扩展类`PieMockitoExtension`\n`PieMockitoExtension`会在每个测试方法执行前初始化拥有注解`@Mock`和`@MockPrimay`对象。\n\n```java\n@ExtendWith({ MockitoExtension.class, PieMockitoExtension.class })\npublic class PieMockitoExtensionTest {\n\n  @Mock(lenient = true)\n  @MockPrimary(UserServiceMock.class)\n  private UserService userService;\n\n  @Test\n  public void testPrimary() {\n    assertFalse(userService.delete(1590000));\n    assertTrue(userService.delete(1581111));\n  }\n}\n```\n\n## `@MockProvider`：为某个测试方法提供mock\n`@MockPrimary`提供了快速Mock一个对象的功能，`@MockProvider`则针对每个测试方法准备Mock功能的方法。`@MockPrimary`是一个对象的Mock，`@MockProvider`则每个测试方法需要所有Mock对象的Mock，它是测试方法级别的。\n\n1). 创建测试类的TestClassMock类：\n\n```java\npublic class MockProviderTestClassMock {\n\n  @PieData(\"/pie/list_user_.json\")\n  private List\u003cUser\u003e userList;\n\n  private UserService userService;\n\n  public MockProviderTestClassMock() {\n    Pie.initAnnotations(this);\n  }\n\n  public void mock_testProvider() {\n    given(userService.find(anyLong())).willReturn(userList.get(1));\n  }\n\n}\n```\n\n2). 使用`@MockProvider`指定TestClassMock：\n\n```java\n@ExtendWith({ MockitoExtension.class, PieMockitoExtension.class })\n@MockProvider(MockProviderTestClassMock.class)\npublic class MockProviderTest {\n\n  @Mock(lenient = true)\n  @MockPrimary(UserServiceMock.class)\n  private UserService userService;\n\n  @Test\n  public void testPrimary() {\n    // use primary mock\n    User findUser = userService.find(12306);\n    Assertions.assertEquals(findUser.getName(), \"Sayi\");\n  }\n\n  @Test\n  public void testProvider() {\n    // user provider mock\n    User findUser = userService.find(12306);\n    Assertions.assertEquals(findUser.getName(), \"Van\");\n  }\n\n}\n\n```\n每个测试方法会自动寻找`@MockProvider`指定类的前缀为mock_的同名方法去初始化Mock功能，比如testProvider方法执行前会执行MockProviderTestClassMock的mock_testProvider方法。\n\n`@MockProvider`的Mock功能会覆盖`@MockPrimary`的功能，即优先级更高。\n\n## 愿景\n希望TestPie未来能带来更好的単测编码体验。\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsayi%2Ftestpie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsayi%2Ftestpie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsayi%2Ftestpie/lists"}