【发布时间】:2017-01-31 22:24:18
【问题描述】:
我认为这是一个常见的问题,但我找不到任何对我有帮助的东西。我对 Java 比较陌生,并且正在申请工作。为此,我开始编写一个工具来转换数据。 (例如,读取 CSV,翻译一些列并将其写入为 SQL 插入文件)
如果你有兴趣在这里找到它,我会复制一些代码来回答我的问题:https://github.com/fvosberg/datatransformer
我从一个应该读取 CSV 的类开始(并且通过包含一些应该包含分隔符的字段等会变得更加复杂)。我的 IDE (IntellJ IDEA) 建议尽可能对我的方法使用严格的访问修饰符。为什么要对子类隐藏这些方法(带有私有)?
package de.frederikvosberg.datatransformer;
import java.io.BufferedReader;
import java.io.Reader;
import java.util.*;
class CSVInput {
private final BufferedReader _reader;
private String separator = ",";
public CSVInput(Reader reader) {
_reader = new BufferedReader(reader);
}
public List<SortedMap<String, String>> readAll() throws java.io.IOException {
List<SortedMap<String, String>> result = new LinkedList<>();
List<String> headers = readHeaders();
String line;
while ((line = _reader.readLine()) != null) {
result.add(
colsFromLine(headers, line)
);
}
_reader.close();
return result;
}
private List<String> readHeaders() throws java.io.IOException {
List<String> headers = new ArrayList<>();
String line = _reader.readLine();
if (line == null) {
throw new RuntimeException("There is no first line for the headers in the CSV");
}
return valuesFromLine(line);
}
public void setSeparator(String separator) {
this.separator = separator;
}
/**
* creates a list of values from a CSV line
* it uses the separator field
*
* @param line a line with values separated by this.separator
* @return a list of values
*/
private List<String> valuesFromLine(String line) {
return Arrays.asList(
line.split(this.separator)
);
}
private SortedMap<String, String> colsFromLine(List<String> headers, String line) {
SortedMap<String, String> cols = new TreeMap<>();
List<String> values = valuesFromLine(line);
Iterator<String> headersIterator = headers.iterator();
Iterator<String> valuesIterator = values.iterator();
while (headersIterator.hasNext() && valuesIterator.hasNext()) {
cols.put(headersIterator.next(), valuesIterator.next());
}
if (headersIterator.hasNext() || valuesIterator.hasNext()) {
throw new RuntimeException("The size of a row doesn't fit with the size of the headers");
}
return cols;
}
}
另一个缺点是单元测试。我想为我的方法编写单独的测试。尤其是 CSVInput::valuesFromLine 方法,它会变得更加复杂。我对这个类的单元测试测试了这么多,我真的不想在开发时脑子里有很多东西。
有经验的 Java 程序员有什么建议吗?
提前致谢
回复 cmets
感谢您的 cmets。为了清楚起见,让我在这里回答 cmets。
“我为什么要从子类中隐藏这些方法(私有)?”为什么 您是否将车钥匙远离前门?
出于安全考虑,为什么我更改colsFromLine方法的访问修饰符时会影响安全?此方法接受标头作为参数,因此它不依赖任何内部状态,也不更改它。
我能想到的严格访问修饰符的下一个优点是帮助其他开发人员向他们展示他应该使用哪种方法以及逻辑属于哪里。
不要将测试编写为依赖于 功能,只需编写一个测试来验证功能。
我没有。这取决于您对内部实施的含义。我不检查任何内部状态或变量。我只是想测试将逐步解析 CSV 的算法。
“我对这个类的单元测试测试太多了” - 如果测试太多 在课堂上,你应该重新考虑你的设计。很有可能你的 类字面上做的太多了,应该分解。
我的课堂上没有太多测试,但是当我按照我开始的方式进行时,我将为同一个方法(解析 CSV)编写许多测试,因为它有很多边缘情况。由于不同的样板,测试的规模会增加。这就是我在这里问的原因
【问题讨论】:
-
“我为什么要从子类中隐藏这些方法(私有)?”为什么你的车钥匙远离你的前门?
-
不要编写测试依赖于功能的内部实现,只需编写测试来验证功能。如果您稍后决定更改您的实现,您的测试应该能够告诉您新的实现仍然产生正确的结果。如果您正在测试您的实现,那么这将不起作用。
-
“我的这个类的单元测试测试太多了” - 如果一个类的测试太多,你应该重新考虑你的设计。很可能您的班级确实做得太多,应该被打散。
-
谢谢,这很快;-)
标签: java unit-testing junit tdd software-design