ํ˜•์‹์„ ๋งž์ถ”๋Š” ๋ชฉ์ 

์ฝ”๋“œ ํ˜•์‹์€ ์˜์‚ฌ์†Œํ†ต์˜ ์ผํ™˜์ด๋‹ค. ์˜ค๋žœ ์‹œ๊ฐ„์ด ์ง€๋‚˜ ์›๋ž˜ ์ฝ”๋“œ์˜ ํ”์ ์„ ์ฐพ์•„๋ณด๊ธฐ ์–ด๋ ค์šธ ์ •๋„๋กœ ๋ณ€๊ฒฝ๋˜์–ด๋„ ๋งจ ์ฒ˜์Œ ์žก์•„๋†“์€ ๊ตฌํ˜„ ์Šคํƒ€์ผ๊ณผ ๊ฐ€๋…์„ฑ ์ˆ˜์ค€์€ ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ๊ณผ ํ™•์žฅ์„ฑ์— ๊ณ„์† ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.

์ ๋‹นํ•œ ํ–‰ ๊ธธ์ด๋ฅผ ์œ ์ง€ํ•˜๋ผ

์œ„์˜ Box-Plot๋Š” ํ”„๋กœ์ ํŠธ ๋ณ„ ํŒŒ์ผ ๊ธธ์ด๋ฅผ ๋กœ๊ทธ ๋ถ„ํฌ๋กœ ๋‚˜ํƒ€๋‚ธ ์‚ฌ์ง„์ด๋‹ค. ์ฆ‰, ์„ธ๋กœ์ธก์ด ์กฐ๊ธˆ๋งŒ ์ฐจ์ด๋‚˜๋„ ์‹ค์ œ ํ–‰์ˆ˜๋Š” ํฌ๊ฒŒ ์ฐจ์ด๋‚œ๋‹ค๋Š” ๋ง์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์•Œ ์ˆ˜ ์žˆ๋Š”์ ์€ 500์ค„์„ ๋„˜์ง€ ์•Š๊ณ  200์ค„์„ ๊ฐ€์ง€๋Š” ํŒŒ์ผ๋“ค๋กœ๋„ ์ถฉ๋ถ„ํžˆ ์ปค๋‹ค๋ž€ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.

์‹ ๋ฌธ ๊ธฐ์‚ฌ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ผ

์šฐ๋ฆฌ๊ฐ€ ์‹ ๋ฌธ ๊ธฐ์‚ฌ๋ฅผ ์ฝ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์ฝ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด์ž. ๋จผ์ € ์ œ๋ชฉ์„ ๋ณด๊ณ  ์ฝ์„์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•˜๊ณ , ๊ฐ€์žฅ ์ตœ์ƒ๋‹น์˜ ์š”์•ฝ๋œ ๋ฌธ๋‹จ์„ ์ฝ๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋” ์ฝ์„์ง€ ๋ง์ง€ ๊ณ ๋ฏผํ•œ๋‹ค. ๊ทธ ์•„๋ ˆ์—๋Š” ์„ธ์„ธํ•œ ๋‚ด์šฉ๋“ค์ด ์ •๋ฆฌ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์†Œ์ŠคํŒŒ์ผ๋„ ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฆ„๋งŒ ๋ณด๊ณ ๋„ ์˜ฌ๋ฐ”๋ฅธ ๋ชจ๋“ˆ์ธ์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์„ ์ •๋„๋กœ ์‹ ๊ฒฝ์“ฐ์ž. ์ฒซ๋ถ€๋ถ„์—๋Š” ๊ณ ์ถ”์ƒ ์ˆ˜์ค€ ๊ฐœ๋…์„ ์„ค๋ช…ํ•˜๊ณ , ํ•˜์œ„๋กœ ๊ฐˆ์ˆ˜๋ก ์„ธ๋ถ€์‚ฌํ•ญ์„ ๊ธฐ์ˆ ํ•˜์ž.

๊ฐœ๋…์„ ๋นˆ ํ–‰์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋ผ

์ฝ”๋“œ์˜ ๊ฐ ์ค„์€ ์ˆ˜์‹์ด๋‚˜ ์ ˆ์„ ๋‚˜ํƒ€๋‚ด๊ณ , ์—ฌ๋Ÿฌ ์ค„์˜ ๋ฌถ์Œ์€ ์™„๊ฒฐ๋œ ์ƒ๊ฐ ํ•˜๋‚˜๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค. ์ƒ๊ฐ ์‚ฌ์ด์—๋Š” ๋นˆ ํ–‰์„ ๋„ฃ์–ด ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค์ž.

// ๋นˆ ํ–‰์„ ๋„ฃ์ง€ ์•Š์„ ๊ฒฝ์šฐ
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
	public static final String REGEXP = "'''.+?'''";
	private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
		Pattern.MULTILINE + Pattern.DOTALL);
	public BoldWidget(ParentWidget parent, String text) throws Exception {
		super(parent);
		Matcher match = pattern.matcher(text); match.find(); 
		addChildWidgets(match.group(1));}
	public String render() throws Exception { 
		StringBuffer html = new StringBuffer("<b>"); 		
		html.append(childHtml()).append("</b>"); 
		return html.toString();
	} 
}
/ ๋นˆ ํ–‰์„ ๋„ฃ์„ ๊ฒฝ์šฐ
package fitnesse.wikitext.widgets;
 
import java.util.regex.*;
 
public class BoldWidget extends ParentWidget {
	public static final String REGEXP = "'''.+?'''";
	private static final Pattern pattern = Pattern.compile("'''(.+?)'''", 
		Pattern.MULTILINE + Pattern.DOTALL
	);
	
	public BoldWidget(ParentWidget parent, String text) throws Exception { 
		super(parent);
		Matcher match = pattern.matcher(text);
		match.find();
		addChildWidgets(match.group(1)); 
	}
	
	public String render() throws Exception { 
		StringBuffer html = new StringBuffer("<b>"); 
		html.append(childHtml()).append("</b>"); 
		return html.toString();
	} 
}

์„ธ๋กœ ๋ฐ€์ง‘๋„

์ค„ ๋ฐ”๊ฟˆ์ด ๊ฐœ๋…์„ ๋ถ„๋ฆฌํ•œ๋‹ค๋ฉด, ์„ธ๋กœ ๋ฐ€์ง‘๋„๋Š” ์—ฐ๊ด€์„ฑ์„ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰, ์„œ๋กœ ๋ฐ€์ ‘ํ•œ ์ฝ”๋“œ ํ–‰์€ ์„ธ๋กœ๋กœ ๊ฐ€๊นŒ์ด ๋†“์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

// ์˜๋ฏธ์—†๋Š” ์ฃผ์„์œผ๋กœ ๋ณ€์ˆ˜๋ฅผ ๋–จ์–ด๋œจ๋ ค ๋†“์•„์„œ ํ•œ๋ˆˆ์— ํŒŒ์•…์ด ์ž˜ ์•ˆ๋œ๋‹ค.
 
public class ReporterConfig {
	/**
	* The class name of the reporter listener 
	*/
	private String m_className;
	
	/**
	* The properties of the reporter listener 
	*/
	private List<Property> m_properties = new ArrayList<Property>();
	public void addProperty(Property property) { 
		m_properties.add(property);
	}
// ์˜๋ฏธ ์—†๋Š” ์ฃผ์„์„ ์ œ๊ฑฐํ•จ์œผ๋กœ์จ ์ฝ”๋“œ๊ฐ€ ํ•œ๋ˆˆ์— ๋“ค์–ด์˜จ๋‹ค.
// ๋ณ€์ˆ˜ 2๊ฐœ์— ๋ฉ”์†Œ๋“œ๊ฐ€ 1๊ฐœ์ธ ํด๋ž˜์Šค๋ผ๋Š” ์‚ฌ์‹ค์ด ๋“œ๋Ÿฌ๋‚œ๋‹ค.
 
public class ReporterConfig {
	private String m_className;
	private List<Property> m_properties = new ArrayList<Property>();
	
	public void addProperty(Property property) { 
		m_properties.add(property);
	}

์ˆ˜์ง ๊ฑฐ๋ฆฌ

ํ•จ์ˆ˜ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ํ†ตํ•œ ๋™์ž‘ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๋ ค๊ณ  ์ด ํ•จ์ˆ˜, ์ € ํ•จ์ˆ˜๋ฅผ ์˜ค๊ฐ€๋ฉด์„œ ์œ„ ์•„๋ž˜๋กœ ์ฐพ์•„ ํ•ด๋ฉจ๋˜ ๊ฒฝํ—˜์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ˜น์€ ์ƒ์†๊ด€๊ณ„๋ฅผ ์ค„์ค„ํžˆ ๊ฑฐ์Šฌ๋Ÿฌ์„œ ์˜ฌ๋ผ๊ฐ„ ๊ฒฝํ—˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋ณ„๋กœ ์ข‹์€ ๊ฒฝํ—˜์œผ๋กœ ๋‚จ์ง€ ์•Š์•˜์„ ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๋‹ฌ๊ฐ‘์ง€ ์•Š์€ ๊ฒฝํ—˜์˜ ๋ณธ์งˆ์—๋Š” ์–ด๋””์— ์žˆ๋Š”์ง€ ์ฐพ๊ณ  ๊ธฐ์–ตํ•˜๋Š”๋ฐ ์žˆ์–ด ๋…ธ๋ ฅ์„ ์†Œ๋ชจํ–ˆ๋‹ค๋Š” ์ ์— ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋ฐ€์ ‘ํ•œ ๊ฐœ๋…์„ ์„ธ๋กœ์— ๋‘๋Š” ๋…ธ๋ ฅ์ด ํ•„์š”ํ•˜๋‹ค. ๋‘ ๊ฐœ๋…์ด ์„œ๋กœ ๋‹ค๋ฅธ ํŒŒ์ผ์— ์†ํ•œ๋‹ค๋ฉด ์ด ๊ทœ์น™์ด ํ†ตํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ํƒ€๋‹นํ•œ ๊ทผ๊ฑฐ๊ฐ€ ์—†๋‹ค๋ฉด ํ•œ ํŒŒ์ผ์•ˆ์— ํ•ด๋‹น ๊ฐœ๋…์ด ์†ํ•˜๋Š” ๊ฒƒ์ด ๋งˆ๋•…ํ•˜๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ, ๊ฐ™์€ ํŒŒ์ผ์•ˆ์— ์†ํ•  ์ •๋„๋กœ ๋ฐ€์ ‘ํ•œ ๋‘ ๊ฐœ๋…์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์„ธ๋กœ ๊ฑฐ๋ฆฌ๋กœ ์—ฐ๊ด€์„ฑ์„ ํ‘œํ˜„ํ•˜์ž. ์ง€๋‚˜์น˜๊ฒŒ ๋ฉ€๋ฆฌ ๋–จ์–ด์ ธ ์žˆ์œผ๋ฉด ์ฝ๋Š” ์‚ฌ๋žŒ์ด ์—ฌ๊ธฐ์ €๊ธฐ๋ฅผ ๋’ค์ ธ์•ผ ํ•œ๋‹ค.

๋ณ€์ˆ˜ ์„ ์–ธ

๋ณ€์ˆ˜๋Š” ์‚ฌ์šฉํ•˜๋Š” ์œ„์น˜์— ์ตœ๋Œ€ํ•œ ๊ฐ€๊นŒ์ด ์„ ์–ธํ•˜์ž. ์šฐ๋ฆฌ๊ฐ€ ์„ค๊ณ„ํ•œ ํ•จ์ˆ˜๋Š” ๋งค์šฐ ์งง์œผ๋ฏ€๋กœ (3์žฅ: ํ•จ์ˆ˜) ์ง€์—ญ ๋ณ€์ˆ˜๋Š” ๊ฐ ํ•จ์ˆ˜ ๋งจ ์ฒ˜์Œ์— ์„ ์–ธํ•˜์ž.

// InputStream์ด ํ•จ์ˆ˜ ๋งจ ์ฒ˜์Œ์— ์„ ์–ธ ๋˜์–ด์žˆ๋‹ค. ์–˜๋Š” ์‚ฌ์‹ค ์ข€ ๊ธธ๋‹ค
 
private static void readPreferences() {
	InputStream is = null;
	try {
		is = new FileInputStream(getPreferencesFile()); 
		setPreferences(new Properties(getPreferences())); 
		getPreferences().load(is);
	} catch (IOException e) { 
		try {
			if (is != null) 
				is.close();
		} catch (IOException e1) {
		} 
	}
}
// ๋ชจ๋‘๋“ค ์•Œ๋‹ค์‹œํ”ผ ๋ฃจํ”„ ์ œ์–ด ๋ณ€์ˆ˜๋Š” Test each์ฒ˜๋Ÿผ ๋ฃจํ”„ ๋ฌธ ๋‚ด๋ถ€์— ์„ ์–ธ
 
public int countTestCases() { 
	int count = 0;
	for (Test each : tests) // HERE!
		count += each.countTestCases(); 
	return count;
}
// ๋“œ๋ฌผ์ง€๋งŒ, ๊ธด ํ•จ์ˆ˜์—์„œ๋Š” ๋ธ”๋ก ์ƒ๋‹จ ๋˜๋Š” ๋ฃจํ”„ ์ง์ „์— ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
...
for (XmlTest test : m_suite.getTests()) {
	TestRunner tr = m_runnerFactory.newTestRunner(this, test); // HERE!!
	tr.addListener(m_textReporter); 
	m_testRunners.add(tr);
 
	invoker = tr.getInvoker();
	
	for (ITestNGMethod m : tr.getBeforeSuiteMethods()) { 
		beforeSuiteMethods.put(m.getMethod(), m);
	}
 
	for (ITestNGMethod m : tr.getAfterSuiteMethods()) { 
		afterSuiteMethods.put(m.getMethod(), m);
	} 
}
...

์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜

์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ํด๋ž˜์Šค ๋งจ ์ฒ˜์Œ์— ์„ ์–ธํ•œ๋‹ค(์ž๋ฐ”์˜ ๊ฒฝ์šฐ). ์ž˜ ์„ค๊ณ„ํ•œ ํด๋ž˜์Šค๋Š” ๋Œ€๋‹ค์ˆ˜ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๊ฐ€ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. c++์˜ ๊ฒฝ์šฐ ๋งˆ์ง€๋ง‰์— ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ์–ด๋Š ๊ณณ์ด๋“  ์ž˜ ์•Œ๋ ค์ง„ ์œ„์น˜์— ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ๋ชจ์œผ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

// ๋„์ค‘์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š” ๊ฝ๊ฝ ์ˆจ๊ฒจ๋†“์€ ๋ณด๋ฌผ ์ฐพ๊ธฐ์™€ ๊ฐ™๋‹ค. ์‹ญ์ค‘ ํŒ”๊ตฌ ์ฝ”๋“œ๋ฅผ ์ฝ๋‹ค๊ฐ€ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ•œ๋‹ค. ๋ฐœ๊ฒฌํ•ด๋ณด์‹œ๊ธธ.
// ์š”์ฆ˜์€ IDE๊ฐ€ ์ž˜ ๋˜์–ด์žˆ์–ด์„œ ์ฐพ๊ธฐ์•ผ ์–ด๋ ต์ง€ ์•Š๊ฒ ์ง€๋งŒ, ๋”๋Ÿฌ์šด๊ฑด ๋งˆ์ฐฌ๊ฐ€์ง€
 
public class TestSuite implements Test {
	static public Test createTest(Class<? extends TestCase> theClass,
									String name) {
		... 
	}
 
	public static Constructor<? extends TestCase> 
	getTestConstructor(Class<? extends TestCase> theClass) 
	throws NoSuchMethodException {
		... 
	}
 
	public static Test warning(final String message) { 
		...
	}
	
	private static String exceptionToString(Throwable t) { 
		...
	}
	
	private String fName;
 
	private Vector<Test> fTests= new Vector<Test>(10);
 
	public TestSuite() { }
	
	public TestSuite(final Class<? extends TestCase> theClass) { 
		...
	}
 
	public TestSuite(Class<? extends TestCase> theClass, String name) { 
		...
	}
	
	... ... ... ... ...
}

์ข…์† ํ•จ์ˆ˜

ํ•œ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ๋‘ ํ•จ์ˆ˜๋Š” ์„ธ๋กœ๋กœ ๊ฐ€๊นŒ์ด ๋ฐฐ์น˜ํ•œ๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋ณด๋‹ค ๋จผ์ € ๋ฐฐ์น˜ํ•œ๋‹ค. ์ฆ‰, ๋ณดํ†ต์€ ์ถ”์ƒํ™”๋ ˆ๋ฒจ์ด ์ƒ์œ„์— ๋†’์„ ๊ฒƒ์ด๋ฏ€๋กœ(== ์ €์ˆ˜์ค€ ์ถ”์ƒํ™”ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ) ํ•˜์œ„์— ์ €์ˆ˜์ค€ ์ถ”์ƒํ™” ํ•จ์ˆ˜๋ฅผ ๋‘์ž. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ฝํžŒ๋‹ค. ์ด๋Ÿฐ ๊ทœ์น™์„ ์ ์šฉํ•œ๋‹ค๋ฉด ์ฝ๋Š” ์‚ฌ๋žŒ๋„ ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์„ โ€œ์˜ˆ์ธกโ€ํ•˜๋ฉด์„œ ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

/*์ฒซ์งธ ํ•จ์ˆ˜์—์„œ ๊ฐ€์žฅ ๋จผ์ € ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋ฐ”๋กœ ์•„๋ž˜ ์ •์˜๋œ๋‹ค.
๋‹ค์Œ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๊ทธ ์•„๋ž˜์— ์ •์˜๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง€๋ฉฐ
์ „์ฒด ๊ฐ€๋…์„ฑ๋„ ๋†’์•„์ง„๋‹ค.*/
	
/*makeResponse ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•˜๋Š” getPageNameOrDefaultํ•จ์ˆ˜ ์•ˆ์—์„œ "FrontPage" ์ƒ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ,
์ƒ์ˆ˜๋ฅผ ์•Œ์•„์•ผ ์˜๋ฏธ ์ „๋‹ฌ์ด ์‰ฌ์›Œ์ง€๋Š” ํ•จ์ˆ˜ ์œ„์น˜์—์„œ ์‹ค์ œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ƒ์ˆ˜๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด
๊ฐ€๋…์„ฑ ๊ด€์ ์—์„œ ํ›จ์”ฌ ๋” ์ข‹๋‹ค*/
 
public class WikiPageResponder implements SecureResponder { 
	protected WikiPage page;
	protected PageData pageData;
	protected String pageTitle;
	protected Request request; 
	protected PageCrawler crawler;
	
    // ๊ณ ์ˆ˜์ค€
	public Response makeResponse(FitNesseContext context, Request request) throws Exception {
		String pageName = getPageNameOrDefault(request, "FrontPage");
		loadPage(pageName, context); 
		if (page == null)
			return notFoundResponse(context, request); 
		else
			return makePageResponse(context); 
		}
 
	private String getPageNameOrDefault(Request request, String defaultPageName) {
		String pageName = request.getResource(); 
		if (StringUtil.isBlank(pageName))
			pageName = defaultPageName;
 
		return pageName; 
	}
	
	protected void loadPage(String resource, FitNesseContext context)
		throws Exception {
		WikiPagePath path = PathParser.parse(resource);
		crawler = context.root.getPageCrawler();
		crawler.setDeadEndStrategy(new VirtualEnabledPageCrawler()); 
		page = crawler.getPage(context.root, path);
		if (page != null)
			pageData = page.getData();
	}
	
	private Response notFoundResponse(FitNesseContext context, Request request)
		throws Exception {
		return new NotFoundResponder().makeResponse(context, request);
	}
	
	private SimpleResponse makePageResponse(FitNesseContext context)
		throws Exception {
		pageTitle = PathParser.render(crawler.getFullPath(page)); 
		String html = makeHtml(context);
		SimpleResponse response = new SimpleResponse(); 
		response.setMaxAge(0); 
		response.setContent(html);
		return response;
	} 
...

๊ฐœ๋…์  ์œ ์‚ฌ์„ฑ

๊ฐœ๋…์ ์ธ ์นœํ™”๋„๊ฐ€ ๋†’์„ ์ˆ˜๋ก ์ฝ”๋“œ๋ฅผ ์„œ๋กœ ๊ฐ€๊นŒ์ด ๋ฐฐ์น˜ํ•œ๋‹ค. ์œ„์—์„œ ๋งํ•œ ๋‚ด์šฉ๋“ค์ด ํ•ด๋‹น ๋ฒ”์ฃผ์— ์†ํ•˜๋Š”๋ฐ, ์ฆ‰, ํ•œ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ข…์†์„ฑ, ๋ณ€์ˆ˜์™€ ๊ทธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋“ฑ์ด ๊ทธ ์˜ˆ์ด๋‹ค. ํ˜น์€ ๋น„์Šทํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜ ๋ฌด๋ฆฌ๋„ ๊ทธ ์˜ˆ์— ์†ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

// ๊ฐ™์€ assert ๊ด€๋ จ๋œ ๋™์ž‘๋“ค์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ๋ช…๋ช…๋ฒ•์ด ๋˜‘๊ฐ™๊ณ  ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์ด ์œ ์‚ฌํ•œ ํ•จ์ˆ˜๋“ค๋กœ์จ ๊ฐœ๋…์  ์นœํ™”๋„๊ฐ€ ๋†’๋‹ค.
// ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์ข…์†์„ฑ์€ ์˜คํžˆ๋ ค ๋ถ€์ฐจ์  ์š”์ธ์ด๋ฏ€๋กœ, ์ข…์†์ ์ธ ๊ด€๊ณ„๊ฐ€ ์—†๋”๋ผ๋„ ๊ฐ€๊นŒ์ด ๋ฐฐ์น˜ํ•˜๋ฉด ์ข‹๋‹ค.
 
public class Assert {
	static public void assertTrue(String message, boolean condition) {
		if (!condition) 
			fail(message);
	}
 
	static public void assertTrue(boolean condition) { 
		assertTrue(null, condition);
	}
 
	static public void assertFalse(String message, boolean condition) { 
		assertTrue(message, !condition);
	}
	
	static public void assertFalse(boolean condition) { 
		assertFalse(null, condition);
	} 
...

์„ธ๋กœ ์ˆœ์„œ

์ผ๋ฐ˜์ ์œผ๋กœ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ข…์†์„ฑ์€ ์•„๋ž˜๋ฐฉํ–ฅ์œผ๋กœ ์œ ์ง€ํ•˜๋ฏ€๋กœ, ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋ณด๋‹ค ๋’ค์— ๋ฐฐ์น˜ํ•œ๋‹ค. ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ณ ์ฐจ์›์—์„œ ์ €์ฐจ์›์œผ๋กœ ๋‚ด๋ ค๊ฐ€๋Š” ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฐœ๋…์€ ๊ฐ€์žฅ ์œ„์—, ์„ธ์„ธํ•œ ์‚ฌํ•ญ์€ ๋งˆ์ง€๋ง‰์—.

๊ฐ€๋กœ ํ˜•์‹ ๋งž์ถ”๊ธฐ

์œ„ ํ‘œ๋Š” ๊ฐ€๋กœ์— ํ–‰ ๊ธธ์ด, ์„ธ๋กœ์— ๋กœ๊ทธ ์Šค์ผ€์ผ๋กœ ํ‘œ์‹œ๋œ ํ–‰ ์ˆ˜ ๋ถ„ํฌ์ด๋‹ค. ์ฆ‰, ํŠน์ • ํ–‰ ๊ธธ์ด์— ํ•ด๋‹นํ•˜๋Š” ๋ผ์ธ์ด ๋ช‡ํ”„๋กœ๋‚˜ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œ์ด๋‹ค. ์ž˜ ๋ณด๋ฉด, 20์—์„œ 60์ž ์‚ฌ์ด์ธ ํ–‰์ด ์ดˆ ํ–‰ ์ˆ˜์˜ 40%์— ๋‹ฌํ•œ๋‹ค. 10์ž ๋ฏธ๋งŒ์€ 30% ์ •๋„์ด๊ณ , 80% ์ด์‚ฌ์œผ์ด ๊ฒฝ์šฐ ํ–‰์ˆ˜ ์ ์œ ์œจ์€ ๊ธ‰๊ฒฉํ•˜๊ฒŒ ๊ฐ์†Œํ•œ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ์งง์€ ํ–‰์„ ์„ ํ˜ธํ•œ๋‹ค. ๊ฐ€๋กœํ–‰์€ 120์ž ์ •๋„๋ฅผ ์œ ์ง€ํ•˜์ž

๊ฐ€๋กœ ๊ณต๋ฐฑ๊ณผ ๋ฐ€์ง‘๋„

private void measureLine(String line) { 
	lineCount++;
	
	// ํ”ํžˆ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์ธ๋ฐ, ํ• ๋‹น ์—ฐ์‚ฐ์ž ์ขŒ์šฐ๋กœ ๊ณต๋ฐฑ์„ ์ฃผ์–ด ์™ผ์ชฝ,์˜ค๋ฅธ์ชฝ ์š”์†Œ๊ฐ€ ํ™•์‹คํ•˜๊ฒŒ ๊ตฌ๋ถ„๋œ๋‹ค.
	int lineSize = line.length();
	totalChars += lineSize; 
	
	// ๋ฐ˜๋ฉด ํ•จ์ˆ˜์ด๋ฆ„๊ณผ ๊ด„ํ˜ธ ์‚ฌ์ด์—๋Š” ๊ณต๋ฐฑ์„ ์—†์•ฐ์œผ๋กœ์จ ํ•จ์ˆ˜์™€ ์ธ์ˆ˜์˜ ๋ฐ€์ ‘ํ•จ์„ ๋ณด์—ฌ์ค€๋‹ค
	// ๊ด„ํ˜ธ ์•ˆ์˜ ์ธ์ˆ˜๋ผ๋ฆฌ๋Š” ์‰ผํ‘œ ๋’ค์˜ ๊ณต๋ฐฑ์„ ํ†ตํ•ด ์ธ์ˆ˜๊ฐ€ ๋ณ„๊ฐœ๋ผ๋Š” ์‚ฌ์‹ค์„ ๋ณด์—ฌ์ค€๋‹ค.
	lineWidthHistogram.addLine(lineSize, lineCount);
	recordWidestLine(lineSize);
}

์œ„์˜ ์ฝ”๋“œ ์˜ˆ์‹œ ๋ง๊ณ ๋„ ์—ฐ์‚ฐ์ž ์šฐ์„  ์ˆœ์œ„๋ฅผ ๊ฐ•์กฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

return b*b - 4*a*c;
return (-b + pi) / (2*a)

์ด๋ ‡๊ฒŒ ๊ณต๋ฐฑ์„ ์ ์šฉํ•  ๊ฒฝ์šฐ ์ˆ˜์‹ ์ฝ๊ธฐ๊ฐ€ ๋งค์šฐ ํŽธํ•˜๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋“œ formatter์˜ ๋Œ€๋‹ค์ˆ˜๋Š” ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ณ ๋ คํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ๊ฐ„๊ฒฉ์„ ์ ์šฉํ•œ๋‹ค. (Q ๊ด„ํ˜ธ๋กœ ๋ฌถ์–ด์ฃผ๋Š” ํŒ๋‹จ์€ ์–ด๋–ค์ง€? ํ† ๋ก )

๊ฐ€๋กœ ์ •๋ ฌ

public class FitNesseExpediter implements ResponseSender {
	private		Socket		      socket;
	private 	InputStream 	  input;
	private 	OutputStream 	  output;
	private 	Reques		      request; 		
	private 	Response 	      response;	
	private 	FitNesseContex	  context; 
	protected 	long		      requestParsingTimeLimit;
	private 	long		      requestProgress;
	private 	long		      requestParsingDeadline;
	private 	boolean		      hasError;
	
	... 

๋ณด๊ธฐ์—๋Š” ์—„์ฒญ ์ข‹์•„๋ณด์ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ์‹ค์ œ๋กœ ์ฝ์–ด๋ณด๋ฉด ๋‹ค๋ฅด๋‹ค. ๋ณ€์ˆ˜ ์œ ํ˜•์„ ์ž์—ฐ์Šค๋ ˆ ๋ฌด์‹œํ•˜๊ณ  ์ด๋ฆ„๋ถ€ํ„ฐ ์ฝ๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Code formmater๊ฐ€ ๋ฌด์‹œํ•˜๊ณ  ์›๋ž˜๋Œ€๋กœ ๋Œ๋ ค๋†“๋Š”๋‹ค. ์„ ์–ธ๋ถ€๊ฐ€ ๊ธธ๋‹ค๋ฉด ์˜คํžˆ๋ ค ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š” ํ•„์š”์„ฑ์ด ์žˆ์Œ์„ ๋งํ•œ๋‹ค.

๋“ค์—ฌ์“ฐ๊ธฐ

๋“ค์—ฌ์“ฐ๊ธฐ๋Š” ๋ฒ”์œ„๋กœ ์ด๋ค„์ง„ ๊ณ„์ธต์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค.

๋“ค์—ฌ์“ฐ๊ธฐ ๋ฌด์‹œํ•˜๊ธฐ

๊ฐ„๋‹จํ•œ if๋ฌธ, while๋ฌธ, ์งง์€ ํ•จ์ˆ˜์—์„œ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๋ฌด์‹œํ•˜๊ณ ํ”ˆ ์œ ํ˜น์ด ์ƒ๊ธด๋‹ค.

// ์ด๋ ‡๊ฒŒ ํ•œํ–‰์— ๋‹ค ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋‹ค ๋•Œ๋ ค ๋ฐ•๋Š” ๊ฒƒ์ด ๋ฉ‹์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ž€ ๊ฒƒ! ์•Œ์•„๋‘์‚ผ
 
public class CommentWidget extends TextWidget {
	public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
	
	public CommentWidget(ParentWidget parent, String text){super(parent, text);}
	public String render() throws Exception {return ""; } 
}
// ํ•œ์ค„์ด๋ผ๋„ ์ •์„ฑ์Šค๋Ÿฝ๊ฒŒ ๋“ค์—ฌ์“ฐ๊ธฐ๋กœ ๊ฐ์‹ธ์ฃผ์ž. ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด
 
public class CommentWidget extends TextWidget {
	public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
	
	public CommentWidget(ParentWidget parent, String text){
		super(parent, text);
	}
	
	public String render() throws Exception {
		return ""; 
	} 
}

ํ•œ์ค„์— ๋„ฃ์€ ๊ฒƒ๋ณด๋‹ค ๊ฐœํ–‰ํ•œ ๊ฒƒ์ด ํ›จ์”ฌ ์ž˜ ์ฝํžŒ๋‹ค.

๊ฐ€์งœ ๋ฒ”์œ„

๋นˆ while ๋ฌธ์ด๋‚˜ for๋ฌธ์„ ์ ‘ํ•˜๋Š” ๊ฒฝ์šฐ ๋นˆ ๋ธ”๋ก์„ ๋“ค์—ฌ์“ฐ๊ณ  ๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ์ž.

while (dis.readbuf, 0, readBufferSize) != -1)
;

์ด๋ ‡๊ฒŒ ํ•ด์•ผ ๋ˆˆ์— ๋ˆ๋‹ค๊ณ  ํ•œ๋‹ค. (?? ์งˆ๋ฌธ)

ํŒ€ ๊ทœ์น™

์ฝ”๋”ฉ ์Šคํƒ€์ผ์„ ์˜๋…ผํ•˜์—ฌ(๊ด„ํ˜ธ๋ฅผ ์–ด๋””์— ๋„ฃ์„์ง€, ๋„ค์ด๋ฐ์€ ์–ด๋–ป๊ฒŒ ํ• ์ง€ ๋“ฑ) IDE Formatter๋กœ ์ง€์ •ํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์˜ณ์€ ๋ฐฉ์‹์ด๋‹ค. ์ข‹์€ ์†Œํ”„ํŠธ์›จ์–ด ์‹œ์Šคํ…œ์€ ์ฝ๊ธฐ ์‰ฌ์šด ๋ฌธ์„œ๋กœ ์ด๋ค„์ง€๊ณ , ์ฝ๊ธฐ ์‰ฌ์šด ๋ฌธ์„œ๋Š” ์Šคํƒ€์ผ์ด ์ผ๊ด€์ ์ด๊ณ  ๋งค๋„๋Ÿฌ์›Œ์•ผ ํ•œ๋‹ค.

๋ฐฅ ์•„์ €์”จ์˜ ํ˜•์‹ ๊ทœ์น™

๋์œผ๋กœ ์ €์ž๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ทœ์น™์ด ์ ์šฉ๋œ ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•œ๋‹ค.

public class CodeAnalyzer implements JavaFileAnalysis { 
	private int lineCount;
	private int maxLineWidth;
	private int widestLineNumber;
	private LineWidthHistogram lineWidthHistogram; 
	private int totalChars;
	
	public CodeAnalyzer() {
		lineWidthHistogram = new LineWidthHistogram();
	}
	
	public static List<File> findJavaFiles(File parentDirectory) { 
		List<File> files = new ArrayList<File>(); 
		findJavaFiles(parentDirectory, files);
		return files;
	}
	
	private static void findJavaFiles(File parentDirectory, List<File> files) {
		for (File file : parentDirectory.listFiles()) {
			if (file.getName().endsWith(".java")) 
				files.add(file);
			else if (file.isDirectory()) 
				findJavaFiles(file, files);
		} 
	}
	
	public void analyzeFile(File javaFile) throws Exception { 
		BufferedReader br = new BufferedReader(new FileReader(javaFile)); 
		String line;
		while ((line = br.readLine()) != null)
			measureLine(line); 
	}
	
	private void measureLine(String line) { 
		lineCount++;
		int lineSize = line.length();
		totalChars += lineSize; 
		lineWidthHistogram.addLine(lineSize, lineCount);
		recordWidestLine(lineSize);
	}
	
	private void recordWidestLine(int lineSize) { 
		if (lineSize > maxLineWidth) {
			maxLineWidth = lineSize;
			widestLineNumber = lineCount; 
		}
	}
 
	public int getLineCount() { 
		return lineCount;
	}
 
	public int getMaxLineWidth() { 
		return maxLineWidth;
	}
 
	public int getWidestLineNumber() { 
		return widestLineNumber;
	}
 
	public LineWidthHistogram getLineWidthHistogram() {
		return lineWidthHistogram;
	}
	
	public double getMeanLineWidth() { 
		return (double)totalChars/lineCount;
	}
 
	public int getMedianLineWidth() {
		Integer[] sortedWidths = getSortedWidths(); 
		int cumulativeLineCount = 0;
		for (int width : sortedWidths) {
			cumulativeLineCount += lineCountForWidth(width); 
			if (cumulativeLineCount > lineCount/2)
				return width;
		}
		throw new Error("Cannot get here"); 
	}
	
	private int lineCountForWidth(int width) {
		return lineWidthHistogram.getLinesforWidth(width).size();
	}
	
	private Integer[] getSortedWidths() {
		Set<Integer> widths = lineWidthHistogram.getWidths(); 
		Integer[] sortedWidths = (widths.toArray(new Integer[0])); 
		Arrays.sort(sortedWidths);
		return sortedWidths;
	} 
}

์š”์•ฝ

  • ํ˜•์‹์€ ํŒ€์—์„œ ํ˜‘์˜ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ํ•œ๋‹ค.
  • ๊ฐœ๋…์„ ๋ชจ์•„์„œ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ๊ณ ์ˆ˜์ค€์—์„œ ์ €์ˆ˜์ค€์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์งœ๋ผ.
  • ํ–‰ ์ˆ˜๋Š” 40-80, ํ–‰ ๊ธธ์ด์€ 120

Reference