组织机构代码输入测试用例_测试代码以用于过大的输入
組織機構代碼輸入測試用例
在編寫單元測試時,我們主要關注業務的正確性。 我們將竭盡所能,開開心心地走在最前沿。 我們有時會進行微基準測試并衡量吞吐量。 但是經常遺漏的一個方面是當輸入過大時我們的代碼如何表現? 我們測試了如何處理正常的輸入文件,格式錯誤的文件,空文件,丟失的文件……但是對于超大的輸入文件呢?
讓我們從一個真實的用例開始。 您已獲得將GPX ( GPS交換格式 ,基本上為XML)實現為JSON轉換的任務。 我之所以選擇GPX并不是出于特殊原因,它只是您可能遇到的另一種XML格式,例如在用GPS接收器記錄遠足或騎自行車時。 我還認為使用XML中的一些標準而不是另一個“人員數據庫”會很好。 在GPX文件中,有數百個平面<wpt/>條目,每個條目代表時空的一個點:
<gpx><wpt lat="42.438878" lon="-71.119277"><ele>44.586548</ele><time>2001-11-28T21:05:28Z</time><name>5066</name><desc><![CDATA[5066]]></desc><sym>Crossing</sym><type><![CDATA[Crossing]]></type></wpt><wpt lat="42.439227" lon="-71.119689"><ele>57.607200</ele><time>2001-06-02T03:26:55Z</time><name>5067</name><desc><![CDATA[5067]]></desc><sym>Dot</sym><type><![CDATA[Intersection]]></type></wpt><!-- ...more... --> </gpx>完整示例: www.topografix.com/fells_loop.gpx 。 我們的任務是提取每個單獨的<wpt/>元素,丟棄沒有lat或lon屬性的元素,并以以下格式存儲回JSON:
[{"lat": 42.438878,"lon": -71.119277},{"lat": 42.439227,"lon": -71.119689}...more... ]這很簡單! 首先,我從使用JDK和GPX 1.0 XSD架構的 xjc實用程序生成JAXB類開始。 請注意,GPX 1.1是撰寫本文時的最新版本,但是我得到的示例使用1.0。 對于JSON編組,我使用了Jackson 。 完整,可運行且經過測試的程序如下所示:
import org.apache.commons.io.FileUtils; import org.codehaus.jackson.map.ObjectMapper; import javax.xml.bind.JAXBException;public class GpxTransformation {private final ObjectMapper jsonMapper = new ObjectMapper();private final JAXBContext jaxbContext;public GpxTransformation() throws JAXBException {jaxbContext = JAXBContext.newInstance("com.topografix.gpx._1._0");}public void transform(File inputFile, File outputFile) throws JAXBException, IOException {final List<Gpx.Wpt> waypoints = loadWaypoints(inputFile);final List<LatLong> coordinates = toCoordinates(waypoints);dumpJson(coordinates, outputFile);}private List<Gpx.Wpt> loadWaypoints(File inputFile) throws JAXBException, IOException {String xmlContents = FileUtils.readFileToString(inputFile, UTF_8);final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();final Gpx gpx = (Gpx) unmarshaller.unmarshal(new StringReader(xmlContents));return gpx.getWpt();}private static List<LatLong> toCoordinates(List<Gpx.Wpt> waypoints) {return waypoints.stream().filter(wpt -> wpt.getLat() != null).filter(wpt -> wpt.getLon() != null).map(LatLong::new).collect(toList());}private void dumpJson(List<LatLong> coordinates, File outputFile) throws IOException {final String resultJson = jsonMapper.writeValueAsString(coordinates);FileUtils.writeStringToFile(outputFile, resultJson);}}class LatLong {private final double lat;private final double lon;LatLong(Gpx.Wpt waypoint) {this.lat = waypoint.getLat().doubleValue();this.lon = waypoint.getLon().doubleValue();}public double getLat() { return lat; }public double getLon() { return lon; } }看起來還不錯,盡管我故意留下了一些陷阱。 我們加載GPX XML文件,將航點提取到List ,然后將該列表轉換為輕量級的LatLong對象,首先過濾掉損壞的航點。 最后,我們將List<LatLong>轉儲到磁盤。 然而,有一天,極其漫長的自行車騎行使我們的系統因OutOfMemoryError崩潰。 你知道發生什么了嗎? 上傳到我們的應用程序中的GPX文件很大,比我們預期的要大得多。 現在再看一下上面的實現,并計算在多少個地方分配了必要的內存?
但是,如果要立即進行重構,請就在此處停止! 我們想練習TDD,對嗎? 我們想在代碼中限制WTF /分鐘因素嗎? 我有一個理論,許多“ WTF”不是由粗心和缺乏經驗的程序員引起的。 通常是由于這些周五晚些時候的生產問題,完全出乎意料的輸入和不可預測的副作用。 代碼獲得了越來越多的變通辦法,難以理解的重構,以及比人們預期的更復雜的邏輯。 有時不希望使用錯誤的代碼,但是由于我們早已忘記了這種情況,因此需要使用錯誤的代碼。 因此,如果有一天您看到不可能發生的null檢查或可能已被庫替換的手寫代碼,請考慮上下文。 話雖這么說,讓我們從編寫測試證明我們的未來重構開始。 如果有一天某人“固定”我們的代碼,并假設“這位愚蠢的程序員”在沒有充分理由的情況下使事情復雜化,那么自動化測試將準確地說明原因 。
我們的測試將僅嘗試轉換瘋狂的大輸入文件。 但是在開始之前,我們必須對原始實現進行一些重構,以使它實現InputStream和OutputStream而不是輸入和輸出File -沒有理由將我們的實現僅限于文件系統:
步驟0a:使其可測試
import org.apache.commons.io.IOUtils;public class GpxTransformation {//...public void transform(File inputFile, File outputFile) throws JAXBException, IOException {try (InputStream input =new BufferedInputStream(new FileInputStream(inputFile));OutputStream output =new BufferedOutputStream(new FileOutputStream(outputFile))) {transform(input, output);}}public void transform(InputStream input, OutputStream output) throws JAXBException, IOException {final List<Gpx.Wpt> waypoints = loadWaypoints(input);final List<LatLong> coordinates = toCoordinates(waypoints);dumpJson(coordinates, output);}private List<Gpx.Wpt> loadWaypoints(InputStream input) throws JAXBException, IOException {String xmlContents = IOUtils.toString(input, UTF_8);final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();final Gpx gpx = (Gpx) unmarshaller.unmarshal(new StringReader(xmlContents));return gpx.getWpt();}//...private void dumpJson(List<LatLong> coordinates, OutputStream output) throws IOException {final String resultJson = jsonMapper.writeValueAsString(coordinates);output.write(resultJson.getBytes(UTF_8));}}步驟0b:編寫輸入(壓力)測試
輸入將從頭使用來產生repeat(byte[] sample, int times)實用程序開發較早 。 基本上,我們將重復數百萬次相同的<wpt/>項,并用GPX頁眉和頁腳將其包裝起來,以便其格式正確。 通常,我會考慮將樣本放在src/test/resources ,但我希望此代碼能夠自我包含。 注意,我們既不在乎實際的輸入,也不在乎輸出。 這已經過測試。 如果轉換成功(如果需要,我們可以添加一些超時),那么就可以了。 如果由于任何異常而失敗,很可能是OutOfMemoryError ,則是測試失敗(錯誤):
import org.apache.commons.io.FileUtils import org.apache.commons.io.output.NullOutputStream import spock.lang.Specification import spock.lang.Unrollimport static org.apache.commons.io.FileUtils.ONE_GB import static org.apache.commons.io.FileUtils.ONE_KB import static org.apache.commons.io.FileUtils.ONE_MB@Unroll class LargeInputSpec extends Specification {final GpxTransformation transformation = new GpxTransformation()final byte[] header = """<?xml version="1.0"?><gpxversion="1.0"creator="ExpertGPS 1.1 - http://www.topografix.com"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.topografix.com/GPX/1/0"xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd"><time>2002-02-27T17:18:33Z</time>""".getBytes(UTF_8)final byte[] gpxSample = """<wpt lat="42.438878" lon="-71.119277"><ele>44.586548</ele><time>2001-11-28T21:05:28Z</time><name>5066</name><desc><![CDATA[5066]]></desc><sym>Crossing</sym><type><![CDATA[Crossing]]></type></wpt>""".getBytes(UTF_8)final byte[] footer = """</gpx>""".getBytes(UTF_8)def "Should not fail with OOM for input of size #readableBytes"() {given:int repeats = size / gpxSample.lengthInputStream xml = withHeaderAndFooter(RepeatedInputStream.repeat(gpxSample, repeats))expect:transformation.transform(xml, new NullOutputStream())where:size << [ONE_KB, ONE_MB, 10 * ONE_MB, 100 * ONE_MB, ONE_GB, 8 * ONE_GB, 32 * ONE_GB]readableBytes = FileUtils.byteCountToDisplaySize(size)}private InputStream withHeaderAndFooter(InputStream samples) {InputStream withHeader = new SequenceInputStream(new ByteArrayInputStream(header), samples)return new SequenceInputStream(withHeader, new ByteArrayInputStream(footer))} } 實際上,這里有7個測試,運行GPX到JSON轉換以輸入大小:1 KiB,1 MiB,10 MiB,100 MiB,1 GiB,8 GiB和32 GiB。 我在JDK 8u11x64上使用以下選項運行這些測試: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx1g 。 1 GiB的內存很多,但顯然不能容納整個輸入文件在內存中:
當小測試通過時,高于1 GiB的輸入將快速失敗。
步驟1:避免將整個文件保留在
堆棧跟蹤揭示了問題所在:
java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3326)at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569)at java.lang.StringBuilder.append(StringBuilder.java:190)at org.apache.commons.io.output.StringBuilderWriter.write(StringBuilderWriter.java:138)at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2002)at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)at org.apache.commons.io.IOUtils.toString(IOUtils.java:778)at com.nurkiewicz.gpx.GpxTransformation.loadWaypoints(GpxTransformation.java:56)at com.nurkiewicz.gpx.GpxTransformation.transform(GpxTransformation.java:50)loadWaypoints急切地將input GPX文件加載到String (請參閱: IOUtils.toString(input, UTF_8) ),以便稍后對其進行解析。 這有點愚蠢,尤其是因為JAXB Unmarshaller可以輕松地直接讀取InputStream 。 讓我們修復它:
private List<Gpx.Wpt> loadWaypoints(InputStream input) throws JAXBException, IOException {final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();final Gpx gpx = (Gpx) unmarshaller.unmarshal(input);return gpx.getWpt(); }private void dumpJson(List<LatLong> coordinates, OutputStream output) throws IOException {jsonMapper.writeValue(output, coordinates); }同樣,我們修復了dumpJson因為它首先將JSON轉儲到String ,然后將該String復制到OutputStream 。 結果略好一些,但再次出現1 GiB失敗,這一次是進入Full GC的無限死亡循環并最終拋出:
java.lang.OutOfMemoryError: Java heap spaceat com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyLoader.text(LeafPropertyLoader.java:50)at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.text(UnmarshallingContext.java:527)at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.processText(SAXConnector.java:208)at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:171)at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:609)[...snap...]at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)at com.nurkiewicz.gpx.GpxTransformation.loadWaypoints(GpxTransformation.java:54)at com.nurkiewicz.gpx.GpxTransformation.transform(GpxTransformation.java:47)第2步:(不好)用StAX替換JAXB
我們可以懷疑,現在的主要問題是使用JAXB進行XML解析,JAXB總是將整個XML文件映射到Java對象中。 很難想象為什么將1 GiB文件轉換為對象圖會失敗。 我們希望以某種方式更好地控制讀取XML并將其分塊使用。 傳統上在這種情況下使用SAX,但是SAX API中的推式編程模型非常不便。 SAX使用回調機制,該機制具有很高的侵入性,并且不易讀。 StAX(用于XML的流API)在更高級別上工作,公開了拉模型。 這意味著客戶代碼決定何時以及消耗多少輸入。 這使我們可以更好地控制輸入,并具有更大的靈活性。 為了使您熟悉該API,以下代碼幾乎等同于loadWaypoints() ,但是我跳過了<wpt/>屬性,這些屬性以后不再需要:
private List<Gpx.Wpt> loadWaypoints(InputStream input) throws JAXBException, IOException, XMLStreamException {final XMLInputFactory factory = XMLInputFactory.newInstance();final XMLStreamReader reader = factory.createXMLStreamReader(input);final List<Gpx.Wpt> waypoints = new ArrayList<>();while (reader.hasNext()) {switch (reader.next()) {case XMLStreamConstants.START_ELEMENT:if (reader.getLocalName().equals("wpt")) {waypoints.add(parseWaypoint(reader));}break;}}return waypoints; }private Gpx.Wpt parseWaypoint(XMLStreamReader reader) {final Gpx.Wpt wpt = new Gpx.Wpt();final String lat = reader.getAttributeValue("", "lat");if (lat != null) {wpt.setLat(new BigDecimal(lat));}final String lon = reader.getAttributeValue("", "lon");if (lon != null) {wpt.setLon(new BigDecimal(lon));}return wpt; }看看我們如何明確地向XMLStreamReader請求更多數據? 然而事實是,我們正在使用更多的低級別的API( 和更大量的代碼),并不意味著它必須是更好的,如果使用不當。 我們一直在構建龐大的waypoints列表,因此再次看到OutOfMemoryError也就不足為奇了:
java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3204)at java.util.Arrays.copyOf(Arrays.java:3175)at java.util.ArrayList.grow(ArrayList.java:246)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:220)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:212)at java.util.ArrayList.add(ArrayList.java:443)at com.nurkiewicz.gpx.GpxTransformation.loadWaypoints(GpxTransformation.java:65)at com.nurkiewicz.gpx.GpxTransformation.transform(GpxTransformation.java:52)正是我們所期望的。 好消息是,1個吉布測試通過(1個吉布堆),所以我們有幾分在正確的方向前進。 但是由于GC過多,需要1分鐘才能完成。
步驟3:正確實施StAX
注意,在上一個示例中使用StAX的實現與SAX一樣好。 但是,我選擇StAX的原因是我們現在可以將XML文件轉換為Iterator<Gpx.Wpt> 。 該迭代器僅在被詢問時才懶散地使用XML文件。 以后我們也可以延遲使用該迭代器,這意味著我們不再將整個文件保留在內存中。 迭代器雖然笨拙,但是比直接使用XML或使用SAX回調要好得多:
import com.google.common.collect.AbstractIterator;private Iterator<Gpx.Wpt> loadWaypoints(InputStream input) throws JAXBException, IOException, XMLStreamException {final XMLInputFactory factory = XMLInputFactory.newInstance();final XMLStreamReader reader = factory.createXMLStreamReader(input);return new AbstractIterator<Gpx.Wpt>() {@Overrideprotected Gpx.Wpt computeNext() {try {return tryPullNextWaypoint();} catch (XMLStreamException e) {throw Throwables.propagate(e);}}private Gpx.Wpt tryPullNextWaypoint() throws XMLStreamException {while (reader.hasNext()) {int event = reader.next();switch (event) {case XMLStreamConstants.START_ELEMENT:if (reader.getLocalName().equals("wpt")) {return parseWaypoint(reader);}break;case XMLStreamConstants.END_ELEMENT:if (reader.getLocalName().equals("gpx")) {return endOfData();}break;}}throw new IllegalStateException("XML file didn't finish with </gpx> element, malformed?");}}; }這變得越來越復雜! 我正在使用來自Guava的AbstractIterator來處理乏味的hasNext()狀態。 每當有人嘗試從迭代器中提取下一個Gpx.Wpt項(或調用hasNext() )時,我們都會消耗一點XML,足以返回一個條目。 如果XMLStreamReader遇到XML的結尾( </gpx>標記),我們將通過返回endOfData()通知迭代器結束。 這是一個非常方便的模式,其中XML被懶惰地讀取并通過方便的迭代器提供服務。 僅此實現就消耗很少的,恒定的內存量。 但是,我們將API從List<Gpx.Wpt>更改為Iterator<Gpx.Wpt> ,這將強制更改其余實現:
private static List<LatLong> toCoordinates(Iterator<Gpx.Wpt> waypoints) {final Spliterator<Gpx.Wpt> spliterator =Spliterators.spliteratorUnknownSize(waypoints, Spliterator.ORDERED);return StreamSupport.stream(spliterator, false).filter(wpt -> wpt.getLat() != null).filter(wpt -> wpt.getLon() != null).map(LatLong::new).collect(toList()); }toCoordinates()以前接受List<Gpx.Wpt> 。 迭代器無法直接轉換為Stream ,因此我們需要通過Spliterator笨拙的轉換。 你認為結束了嗎? ! GiB測試通過得更快一些,但要求更高的測試卻像以前一樣失敗了:
java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3175)at java.util.ArrayList.grow(ArrayList.java:246)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:220)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:212)at java.util.ArrayList.add(ArrayList.java:443)at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)at java.util.Iterator.forEachRemaining(Iterator.java:116)at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)at com.nurkiewicz.gpx.GpxTransformation.toCoordinates(GpxTransformation.java:118)at com.nurkiewicz.gpx.GpxTransformation.transform(GpxTransformation.java:58)at com.nurkiewicz.LargeInputSpec.Should not fail with OOM for input of size #readableBytes(LargeInputSpec.groovy:49)請記住,并非總是從實際上消耗大量內存的地方拋出OutOfMemoryError 。 幸運的是,這次并非如此。 仔細查看底部: collect(toList()) 。
步驟4:避免流和收集器
這真令人失望。 溪流和收集器的設計完全是為了支持懶惰。 但是,實際上不可能有效地實現從流到迭代器的收集器(另請參見: Java 8中編寫自定義收集器以及分組,采樣和批處理–自定義收集器的簡介 ),這是一個很大的設計缺陷。 因此,我們必須完全忘記流,并一直使用簡單的迭代器。 迭代器不是很優雅,但是可以逐項消耗輸入,可以完全控制內存消耗。 我們需要一種方法filter()輸入迭代器,丟棄損壞的項并將map()條目map()到另一個表示形式。 番石榴再次提供了一些方便的實用程序,完全替換了stream() :
private static Iterator<LatLong> toCoordinates(Iterator<Gpx.Wpt> waypoints) {final Iterator<Gpx.Wpt> filtered = Iterators.filter(waypoints, wpt -> wpt.getLat() != null && wpt.getLon() != null);return Iterators.transform(filtered, LatLong::new); } Iterator<Gpx.Wpt>在, Iterator<LatLong>出。 沒有進行任何處理,幾乎沒有觸及XML文件,幾乎沒有內存消耗。 幸運的是,Jackson接受了迭代器并透明地讀取它們,從而迭代生成JSON。 因此,存儲器消耗也保持較低。 猜猜是什么,我們做到了!
內存消耗低且穩定,我認為我們可以放心地假設它是恒定的。 我們的代碼處理速度約為40 MiB / s,因此處理32 GiB大約需要14分鐘,不要感到驚訝。 哦,我是否提到我使用-Xmx32M運行了最后一個測試? 沒錯,使用較少的數千倍內存即可成功處理32 GiB,而不會造成任何性能損失。 與最初實施相比,減少了3000倍。 事實上,最后一個使用迭代器的解決方案甚至能夠處理無限的XML流。 這實際上不只是理論上的情況,想象一下某種流API會產生永無止境的消息流…
最終實施
這是我們完整的代碼:
package com.nurkiewicz.gpx;import com.google.common.base.Throwables; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterators; import com.topografix.gpx._1._0.Gpx; import org.codehaus.jackson.map.ObjectMapper;import javax.xml.bind.JAXBException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.util.Iterator;public class GpxTransformation {private static final ObjectMapper jsonMapper = new ObjectMapper();public void transform(File inputFile, File outputFile) throws JAXBException, IOException, XMLStreamException {try (InputStream input =new BufferedInputStream(new FileInputStream(inputFile));OutputStream output =new BufferedOutputStream(new FileOutputStream(outputFile))) {transform(input, output);}}public void transform(InputStream input, OutputStream output) throws JAXBException, IOException, XMLStreamException {final Iterator<Gpx.Wpt> waypoints = loadWaypoints(input);final Iterator<LatLong> coordinates = toCoordinates(waypoints);dumpJson(coordinates, output);}private Iterator<Gpx.Wpt> loadWaypoints(InputStream input) throws JAXBException, IOException, XMLStreamException {final XMLInputFactory factory = XMLInputFactory.newInstance();final XMLStreamReader reader = factory.createXMLStreamReader(input);return new AbstractIterator<Gpx.Wpt>() {@Overrideprotected Gpx.Wpt computeNext() {try {return tryPullNextWaypoint();} catch (XMLStreamException e) {throw Throwables.propagate(e);}}private Gpx.Wpt tryPullNextWaypoint() throws XMLStreamException {while (reader.hasNext()) {int event = reader.next();switch (event) {case XMLStreamConstants.START_ELEMENT:if (reader.getLocalName().equals("wpt")) {return parseWaypoint(reader);}break;case XMLStreamConstants.END_ELEMENT:if (reader.getLocalName().equals("gpx")) {return endOfData();}break;}}throw new IllegalStateException("XML file didn't finish with </gpx> element, malformed?");}};}private Gpx.Wpt parseWaypoint(XMLStreamReader reader) {final Gpx.Wpt wpt = new Gpx.Wpt();final String lat = reader.getAttributeValue("", "lat");if (lat != null) {wpt.setLat(new BigDecimal(lat));}final String lon = reader.getAttributeValue("", "lon");if (lon != null) {wpt.setLon(new BigDecimal(lon));}return wpt;}private static Iterator<LatLong> toCoordinates(Iterator<Gpx.Wpt> waypoints) {final Iterator<Gpx.Wpt> filtered = Iterators.filter(waypoints, wpt ->wpt.getLat() != null &&wpt.getLon() != null);return Iterators.transform(filtered, LatLong::new);}private void dumpJson(Iterator<LatLong> coordinates, OutputStream output) throws IOException {jsonMapper.writeValue(output, coordinates);}}摘要(TL; DR)
如果您沒有足夠的耐心執行所有步驟,則可以參考以下三點:
翻譯自: https://www.javacodegeeks.com/2014/08/testing-code-for-excessively-large-inputs.html
組織機構代碼輸入測試用例
總結
以上是生活随笔為你收集整理的组织机构代码输入测试用例_测试代码以用于过大的输入的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 批处理linux(批处理 Linux)
- 下一篇: gnu大学(linux 大学)