junit best practices

Status
Nicht offen für weitere Antworten.

mouk

Aktives Mitglied
Hi!

Ich beschäftige mich derzeit mit junit. Habe auch schon einige Dokumentation gelesen, darin wird aber nur die grundlegende Benutzung von Junit behandelt.
Deshalb habe ich einige Fragen bezüglich wie man seine Klassen am besten Testen soll:

Angenommen ich habe eine Klasse mit internen Datenstrukturen, die durch Daten in externen Textdateien gefüllt werden. Wie kann ich nun testen, ob die Daten aus den Textdateien korrekt eingelesen und interpretiert werden? Oder testet man so etwas nicht mit junit, sondern nur die Interfaces der Klassen?
Oder soll ich eine Methode machen, von der die Datenstrukturen zurückgeliefert werden, sodass eine Junit-Test-Methode diese verifizieren kann? (aber ist das nicht schlechter Stil?)

Weiters ist mir aufgefallen dass meine Testklassen schnell relativ groß werden, fast so groß wie die Klasse, die ich damit teste. Ist das normal oder mach ich da was falsch?

Habt ihr sonst vielleicht noch nützliche Tipps oder Best Practices im Umgang mit Junit?

Ich hoffe jemand mit mehr Erfahrung als ich kann mir weiterhelfen.

lg, mouk
 
M

maki

Gast
Es gibt viel best Practices für Junit, in Blog-/Artikel- und Buchform (zB. XUnit).
Der Begriff Mock sagt dir etwas?

Wenn du deinen Code zeigst, kann man vielleicht konkretere Tipps geben.
 

mouk

Aktives Mitglied
Danke für die Antwort.

Ich denke ich werde mir mal Junit in Action bestellen um ein besseres Verständnis zu erlangen.
Mit Mock meinst du wahrscheinlich Mock-Objekte?
 

hibulaire

Neues Mitglied
Hallo Zusammen, ich habe ein kleines Problem mit meiner Anwendung. Ich möchte Test für eine Batchprocessor ausführen mit Easymock und Junit. Ich möchte gern die Methoden addBatchExecutionJob() und getBatchResult() testen. Ich benutze Eclipse 3.5 und der Betriebssystem ist Win XP. Hier ist meine Code:
Java:
package de.kdg.sbp2.preprocessor.batch;

import static org.junit.Assert.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.easymock.EasyMock;
import org.junit.*;


public class BatchExecutionJobTest {
	
	private int batch1Value= 10;
	private int batch2Value= 16;
	private int batch3Value= 30;
	private int batch4Value= 55;
	private int batch5Value= 29;
	private String batch1Names= "batch_snmp1";
	private String batch2Names= "batch_snmp2";
	private String batch3Names= "batch_snmp3";
	private String batch4Names= "batch_snmp4";
	private String batch5Names= "batch_snmp5";
	private BatchHandler batchHandler;
	private BatchExecutionJob batchExecutionJob;
	private Map<Integer, String> batchLinesMap;
	private BatchExecutionJob job;
	private int batchId;
	
	@Before
	public void before(){
		batchHandler= EasyMock.createMock(BatchHandler.class);
		batchExecutionJob= new BatchExecutionJob();
		
		batchLinesMap= new HashMap<Integer, String>(){{
			put(batch1Value, batch1Names);
			put(batch2Value, batch2Names);
			put(batch3Value, batch3Names);
			put(batch4Value, batch4Names);
			put(batch5Value, batch5Names);
		}};
	}
	
	@After
	public void after(){
		EasyMock.verify(batchHandler);
	}
	
	@Test
	@SuppressWarnings("Serial")
	public void testAddBatchExecutionJob() throws BatchException{
		
		EasyMock.expect(batchHandler.getBatch(batchId)).andReturn(batchLinesMap);
		EasyMock.replay(batchHandler);
		
		assertNotNull("batchExecutionJob is null", batchExecutionJob);
		assertNotNull("batchHandler is null", batchHandler);
		Map<Integer, String> actual= batchExecutionJob.getBatchMap();
		
		assertNotNull("actual is null", actual);
		
		Map<Integer, String> expected= new HashMap<Integer, String>(){{
			put(batch1Value, batch1Names);
			put(batch2Value, batch2Names);
		}};
		
		assertEquals(expected, actual);
	}
}
und ich bekomme als error bei Testen : java.lang.AssertionError: actual is null.
Unter sind die benötigte Klasse:
Java:
public interface BatchHandler {

	/**
	 * This adds a batch-execution-job to the job-scheduler
	 * of a batch-processor. it returns the id that was given
	 * to the batch by the job-scheduler.
	 * 
	 * @param job			The job to be executed by
	 * 						the batch-processor, with
	 * 						a certain batch and within certain timeFrames.
	 * @return				the id that was given to the
	 * 						batch by the job-scheduler.
	 */
	int addBatchExecutionJob(BatchExecutionJob job);
	
	/**
	 * returns a Map with line numbers as keys and
	 * lines of the batch as values.
	 * 
	 * @param batchId		The id of the batch to be returned.
	 * @return				A Map with line-numbers as 
	 * 						keys and lines of the batch as 
	 * 						values.
	 */
	Map<Integer, String> getBatch(int batchId);
	
	/**
	 * This returns <code>true</code>, if and only if the batch-execution is finished.
	 * 
	 * @param batchId		The id of the batch which is or is not fully executed.
	 * @return				<code>true</code>, if and only if the batch-execution is finished.
	 */
	boolean isJobFinished(int batchId);
	
	/**
	 * This gets the results of the execution of the lines of a
	 * batch. The batch is identified by the <code>batchId</code>.
	 * 
	 * @param batchId		Id of the batch which produced the desired results.
	 * @return				A Map of line numbers as keys and results of the
	 * 						execution of that lines as values.
	 */
	Map<Integer, String> getBatchResults(int batchId);
}
und
Java:
package de.kdg.sbp2.preprocessor.batch;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import de.kdg.sbp2.job.TimeFrame;

/**
 * Objects of this can be used to handle a 
 * batch execution job to the job-scheduler of a batch-processor
 * via a <code>BatchHandler</code>. At least you must set a 
 * batch to this job, either by a file, or by a <code>Reader</code>
 * or by an <code>InputStream</code>. TimeFrames are optional.
 * If there is none, the batch may be executed any time.
 * 
 * 
 * 
 * @see BatchHandler
 */
public class BatchExecutionJob {
	
	public final static int BATCH_MISSING = -1;
	
	private String lineSeparator = System.getProperty("line.separator");
	private Map<Integer, String> batchLinesMap = null;
	private Map<Date, TimeFrame> timeFrameMap;
	private Map<Date, Long> timeSpanMap;
	
	/**
	 * A simple constructor. Don't forget to set a batch, after you
	 * used this.
	 */
	BatchExecutionJob() {
		timeFrameMap = new HashMap<Date, TimeFrame>();
	}
	
	/**
	 * This gets the Map with all the batch lines, and with the 
	 * line numbers as keys.
	 * 
	 * @return				Map which contains the Batch.
	 */
	public Map<Integer, String> getBatchMap() {
		return batchLinesMap;
	}
	
	public Map<Date, TimeFrame> getTimeFrameMap() {
		return timeFrameMap;
	}
	
	public Map<Date, Long> getTimeSpanMap() {
		return timeSpanMap;
	}

	/**
	 * This sets a batch from a file.
	 * 
	 * @param batchFile		The file that contains the batch.
	 */
	public void setBatchFromFile(File batchFile) {
		if (batchFile != null && batchFile.canRead()) {
			Reader reader;
			try {
				reader = new FileReader(batchFile);
				setBatchFromReader(reader);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * This sets a batch from an <code>InputStream</code>.
	 * 
	 * @param stream		The <code>InputStream</code> that
	 * 						contains the batch.
	 */
	public void setBatchFromInputStream(InputStream stream) {
		if (stream != null) {
			Reader reader = new InputStreamReader(stream);
			setBatchFromReader(reader);
		}
	}
	
	/**
	 * This sets a batch from a <code>Reader</code>.
	 * 
	 * @param reader		The <code>Reader</code> that
	 * 						contains the batch.
	 */
	public void setBatchFromReader(Reader reader) {
		if (reader != null) {
			int charsRead = 0;
			String[] lines = null;
			String fileContent = "";
			char[] buffer = new char[80];
			try {
				charsRead = reader.read(buffer);
				while (charsRead != -1) {
					fileContent += String.valueOf(buffer, 0, charsRead);
					charsRead = reader.read(buffer);
				}
				lines = fileContent.split(lineSeparator);
				batchLinesMap = new HashMap<Integer, String>();
				for (int i = 0; i < lines.length; i++) {
					batchLinesMap.put(i+1, lines[i]);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * This adds a timeFrame to the batch, specified by 
	 * begin and end-date.
	 * 
	 * @param beginDate			The time where execution
	 * 							is permitted to start.
	 * @param endDate			The time where execution
	 * 							must stop again.
	 */
	public void addTimeFrame(Date beginDate, Date endDate) {
		TimeFrame timeFrame = new TimeFrame(beginDate.getTime(), endDate.getTime());
		timeFrameMap.put(beginDate, timeFrame);
	}
	
	/**
	 * 	 * This adds a periodic timeFrame to the batch, specified by 
	 * begin and end-date. The <code>timeSpan</code> is a number
	 * of milliseconds between the first and any subsequent starting
	 * times.
	 * 
	 * @param beginDate			The time where execution
	 * 							is permitted to start.
	 * @param endDate			The time where execution
	 * 							must stop again.
	 * @param timeSpan			The number of millisecond between
	 * 							the first and any subsequent starting
	 * 							times.
	 */
	public void addPeriodicTimeFrameMap(Date beginDate, Date endDate, Long timeSpan) {
		addTimeFrame(beginDate, endDate);
		timeSpanMap.put(beginDate, timeSpan);
	}
	
	/**
	 * This checks if the job has all parameters set.
	 * This is fist of all: if a batch is set.
	 * 
	 * @return					True, if a batch is set.
	 */
	public boolean isValid() {
		return batchLinesMap != null;
	}
}
Ich bin für jede Hilfe dankbar.
 

mvitz

Top Contributor
Ich verstehe irgendwie nicht genau, wo dein Problem ist...

du initialisierst im BatchExecutionJob die Map mit dem Wert null. Im Test rufst du getBatchMap auf, welche dann logischerweise diese Map (null) zurück gibt und dein Test schlägt deshalb fehl.

Ich verstehe auch nicht, wieso du vorher die ganzen Mocksachen aufbaust, wenn das Mock Objekt nicht an die zu testende Klasse übergeben wird, der Mock wird nirgendwo benutzt, also brauchst du den doch garnicht...
 

hibulaire

Neues Mitglied
danke mvitz, dass du so schnell auf mein Post geantwortet hast. Allerdings laut mein problem so: ich möchte jedes Batch an einem Batch Controller schicken und testen ob der BatchController dieser Batch bekommen hast. Ich dachte, man könnte es mit Mock Objekte machen.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
9 IDEA IntelliJ Wie kann man ein JUnit Test bei IntelliJ durchführen? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 11
H kann in Eclipse org.junit nicht importieren IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 2
W NetBeans Junit - Test geht nicht mehr IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
J JUnit Tests machen eclipse probleme IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 1
S JUnit Exception expected IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
B Eclipse Eclipse & JUnit: Zusatzhinweise ausgeben? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 6
S Eclipse: JUnit bei jedem Projekt automatisch hinzufügen lassen IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 7
M Junit Reports sind leer IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
S Eclipse eclipse und junit IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 5
achillesat Eclipse RAP und JUnit Integration IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 2
A Junit Tests aus unterschiedlichen Projekten hintereinander ausführen? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
J NetBeans JUnit 4.5: initialization Error caused an ERROR: Test class can only have one constructor IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 4
M Junit Testfall mehrfach ausführen? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
L Eclipse-Projekt aus SVN so auschecken, daß Junit funktioniert IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 6
N Junit: datengetriebene und abhängige tests IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 2
0x7F800000 Wie JUnit auf 4.6 in eclipse updaten? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 17
O Junit und Eclipse IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 2
S JUnit: assertequal für HashSet IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 2
T JUnit: nach fehlgeschlagenem Test nicht abbrechen IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
D Junit und private Methoden IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 3
Y Maven und JUnit IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 4
K [junit] wie Beispiel starten IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 4
T Netbeans 4.1 --> junit library could not be found ? IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 6
Gregorrr Eclipse Best Practice: Multi-Projekt mit Eclipse + EGit (Git) + m2e (Maven) IDEs - Eclipse, IntelliJ IDEA, BlueJ & mehr 9

Ähnliche Java Themen

Neue Themen


Oben