Skip to content

Commit

Permalink
docs: 添加 DBUnit Mockito 的部分代码片段
Browse files Browse the repository at this point in the history
  • Loading branch information
FuckDoctors committed Jul 19, 2024
1 parent 3e910dd commit 9a3464b
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 0 deletions.
78 changes: 78 additions & 0 deletions docs/notes/backend/java/code-snippets/dbunit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
category:
- 笔记
- backend
- code-snippets
tag:
- java
---

# DBUnit 相关代码片段

## 根据不同连接创建不同的数据库连接

```java
private IDatabaseConnection createDatabaseConnection(Connection conn, String schema) {
IDatabaseConnection dbUnitConn = new DatabaseConnection(conn, schema);
DatabaseConfig config = dbUnitConn.getConfig();
config.setProperty(DatabaseConfig.PROPERTY_ESCAPE_PATTERN, "\"?\"");
config.setProperty(DatabaseConfig.FEATURE_ALLOW_EMPTY_FILEDS, true);

String dbName = conn.getMetaData().getDatabaseProductName().toLowerCase();
if (dbName.contains("oracle")) {
// 注意这里没有使用 OracleDataTypeFactory, 而是自己的 MyOracleDataTypeFactory
config.setProperty(DatabaseConfig.PROPERTY_DATETYPE_FACTORY, new MyOracleDataTypeFactory());
} else if (dbName.contains("mysql")) {
config.setProperty(DatabaseConfig.PROPERTY_DATETYPE_FACTORY, new MySqlDataTypeFactory());
config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
}
}
```

## 自定义数据类型

如果想做特殊处理的话,自定义 `DataType`, 然后注册到 `DataTypeFactory`

比如,对于 Oracle 数据库的 `CHAR` 类型,预期值跟实际值比较时,忽略空格后比较。
可以自定义 DataType 来实现。

### 自定义字符串数据类型

```java
public class StringDataTypeIgnoreSpaceDataType extends StringDataType {
public StringDataTypeIgnoreSpaceDataType(String name, int sqlType) {
super(name, sqlType);
}

@Override
protected int compareNonNulls(Object value1, Object value2) throws TypeCastException {
String val1 = (String) value1;
String val2 = (String) value2;

return val1.strip().compareTo(val2.strip());
}
}
```

### 注册到数据类型工厂

```java

public class MyOracleDataTypeFactory extends OracleDataTypeFactory {

// 第二个参数的 sqlType 跟原来的 sqlType 保持一致
public static final DataType MY_CHAR = new StringDataTypeIgnoreSpaceDataType("CHAR", 1);
public static final DataType MY_NCHAR = new StringDataTypeIgnoreSpaceDataType("NCHAR", -15);

@Override
public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException {
if ("CHAR".equals(sqlTypeName)) {
return MY_CHAR;
} else {
return super.createDataType(sqlType, sqlTypeName);
}
}

}

```
109 changes: 109 additions & 0 deletions docs/notes/backend/java/code-snippets/mockito.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
category:
- 笔记
- backend
- code-snippets
tag:
- java
---

# Mockito 相关代码片段

## 参数验证

JUnit 测试时,对应 Mocked 方法,我们可以返回自己想要的返回值或异常,但是有时希望验证一下,我们调用时传的参数是否正确。

此时,可以使用 ArgumentCaptor 来收集参数,进而做验证。

示例:

```java
ArgumentCaptor<TestIn> argCaptor = ArgumentCaptor.forClass(TestIn.class);
// 调用 (注意,这里指定了类型,不指定的话有些时候不能正确执行,比如, dao.find(any()) 就不知实际该匹配哪个,可能返回 null)
testService.doMethod(any(TestIn.class)).thenReturn(1);
// 参数收集
verify(testService).doMethod(argCaptor.captor());
// 参数校验
assertEquals("0", argCaptor.getValue().getInArg());
```

多次调用时的验证:

```java
ArgumentCaptor<TestIn> argCaptor = ArgumentCaptor.forClass(TestIn.class);

// 参数收集
verify(testService, times(2)).doMethod(argCaptor.captor());
List<TestIn> inValues = argCaptor.getAllValues();

// 参数校验
// 第一次调用的参数验证
assertEquals("0", inValues.get(0).getInArg());
// 第二次调用的参数验证
assertEquals("1", inValues.get(1).getInArg());
```

## 编程式返回期待值

```java
when(testService.doMethod(any())).thenAnswer(inv -> {
TestIn in = inv.getArgument(0, TestIn.class);
TestOut out = new TestOut();

out.setA(in.getA());
if ("".equals(in.getB())) {
out.setOb("1");
}

return out;
});

when(testService.doMethod2(eq("1"), any())).thenReturn("0");
```

## 参数为对象时,返回 null (无法正确匹配)

当参数为对象类型时,为了能区分不太的参数,返回不同的内容,需要自定义参数匹配来实现。
单纯的用 `any(InParam.class)` 是无法实现的。

自定义参数匹配示例:

```java
public class MessageMatcher implements ArgumentMatcher<Message> {

private Message left;

// constructors

@Override
public boolean matches(Message right) {
return left.getFrom().equals(right.getFrom()) &&
left.getTo().equals(right.getTo()) &&
left.getText().equals(right.getText()) &&
right.getDate() != null &&
right.getId() != null;
}
}
```

使用:

```java
// 业务代码
MessageDTO messageDTO = new MessageDTO();
messageDTO.setFrom("me");
messageDTO.setTo("you");
messageDTO.setText("Hello, you!");

messageController.createMessage(messageDTO);

// JUnit 代码
Message message = new Message();
message.setFrom("me");
message.setTo("you");
message.setText("Hello, you!");

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));
```

关于自定义参数匹配,可以参考这篇文章: [Mockito ArgumentMatchers](https://www.baeldung.com/mockito-argument-matchers)

0 comments on commit 9a3464b

Please sign in to comment.