é·ããèªåãã¹ãã¨ãã¹ã容æè¨è¨ãçæ¥ã¨ãã¦ãã¾ããããæè¿ã¯è²ã ãªéçãæãã¦å½¢å¼ææ³ã«åãçµãã§ãã¾ãã
ãã®è¨äºã§ã¯ãæ¢åã®èªåãã¹ãã®ã©ãã«éçãæãã¦ãªãå½¢å¼ææ³ãå¿ è¦ãªã®ãã®ç§è¦ã説æãã¾ãããªããç§ãã¾ã å®å ¨ç解ã«ã¯ç¨é ãããééããããããããã¾ããããææããæè¦ã¯ãã² Kuniwak ã¾ã§ããã ããã¨å¬ããã§ãã
èè ã«ã¤ãã¦
ããã°ã©ãã§ããéçºããã»ã¹ãããããããã®èªçºçãªèªåãã¹ããæ¯æ´ããä»äºããã¦ãã¾ãï¼çµæ´ï¼ãããä¸å¹´ã¯ R&D çãªä½ç½®ä»ãã§å½¢å¼ææ³ããã£ã¦ãã¾ãã
èªåãã¹ãã®éç
èªåãã¹ãã¨ã¯
ç§ãããæ°å¹´æ©ãã§ãããã¨ã¯ãiOS ã Web ã¢ããªãªã©ã®ã¢ãã«å±¤ã®ãã°ãå¾æ¥ã®èªåãã¹ãã§è¦ã¤ããããªããã¨ã§ããããã ããããªããã®è©±ã§å§ããã¨ç解ãã¥ããã¨æãã®ã§ç°¡åãªä¾ããåºçºãã¾ãã
ãã®è¨äºã§ããèªåãã¹ãã¨ã¯ä»¥ä¸ã®ããã«ãã¹ã対象ãå®éã«å®è¡ãã¦çµæã確èªããæ¹æ³ãæå³ãã¦ãã¾ãï¼
// èªåã§å®è£ ãã add 㧠1+1 ã 2 ã«ãªãããæ¤è¨¼ããèªåãã¹ãã describe('add', () => { context('when given 1 and 1', () => { it('should return 2', () => { const actual = add(ONE, ONE); const expected = TWO; assert.deepStrictEqual(actual, expected); }); }); });
ãã®ä¾ã§ã¯èªåã§å®è£
ãã add
é¢æ°ã®æåã確èªããããã« add(ONE, ONE)
ã®çµæã TWO
ã¨çãããªããã¨ãæ¤è¨¼ãã¦ãã¾ãã
ãã ã足ãç®ã®åä½ç¢ºèªã¨ã㦠1 + 1 ã ãã確èªãã¦ãå®å¿ã¯ã§ããªãã§ããããããã«å ãã¦å¥ã®ãã¹ãã±ã¼ã¹ã足ãã¦ãããã¨ã«ãªãã¾ãã
ãªããå ã«ä»åã®è©±ã®ååã®ãã¤ã³ããæ示ãã¦ããã¨ããã®ããã«ããã¹ãã±ã¼ã¹ã®è¿½å ããç¶ãã¦ããã¨ã©ã®ããã«èãæ¹ãå¤ããªããã°ãªããªããã¨ãããã¨ã§ãã
ãã¹ãã±ã¼ã¹å¢å ã¸ã®å¯¾å¿ã®éç
ãã¦ã1 + 1 = 2 以å¤ã®ãã¹ãã±ã¼ã¹ã¨ã㦠1 + 0 = 1 ãæ¤è¨¼ãããã¨ããã¨ã次ã®ããã«åããããªåç´ãªãã¹ãã±ã¼ã¹ï¼Single Condition Testï¼ãå¢ãããã¨ã«ãªãã§ãããï¼
describe('add', () => { context('when given 1 and 1', () => { it('should return 2', () => { const actual = add(ONE, ONE); const expected = TWO; assert.deepStrictEqual(actual, expected); }); }); // å¥ã®å ¥åã試ããããªããã¹ãã±ã¼ã¹ãåããã context('when given 1 and 0', () => { it('should return 1', () => { const actual = add(ONE, ZERO); const expected = ONE; assert.deepStrictEqual(actual, expected); }); }); });
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å
ãããæªããªãã§ããã1ã¤ã®ãã¹ãã±ã¼ã¹ã足ããã³ã«8è¡ã»ã©ã®è¨è¿°ãå¿ è¦ãªã®ã¯å°ãè¾ãã§ãã1ãããã§ããã®ä¾ã®ããã«è¤æ°ã®ãã¹ãã±ã¼ã¹ãå ¥åå¤ã ãç°ãªãã¨ã次ã®ãããªå ±éåãå³ãã¾ãï¼Parameterized TestãTable Driven Testã¨å¼ã°ããï¼ï¼
describe('add', () => { [ {lhs: ONE, rhs: ONE, expected: TWO }, {lhs: ONE, rhs: ZERO, expected: ONE }, ] .forEach(({lhs, rhs, expected}) => { context(`(${lhs}, ${rhs})`, () => { it(`should return ${expected}`, () => { const actual = add(lhs, rhs); assert.deepStrictEqual(actual, expected); }); }); }); });
ããããã¨ãæ°ããªãã¹ãã±ã¼ã¹ã足ãã®ã«å¿ è¦ãªè¡æ°ã¯ãã£ãã®1è¡ã¨ãªãä¿å®ã楽ã«ãªãã¾ããããã¾ã§ã¯èªåãã¹ãã§ãä½è£ã§å¯¾å¿ã§ãã¾ãã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test
ã¨ããã§ãä»åã®ãã¹ã対象ã§ãã足ãç®ããã¡ãã¨å®è£ ã§ããã¨å®å¿ã§ãããã¹ãã±ã¼ã¹ã®æ°ã¯ã©ããããã§ããããï¼å°ãªãã¨ããã¾è©¦ãã2ã¤ã ãã§ã¯å®å¿ã§ããªãã¯ãã§ãããã®ãããªã¨ãã«ãã¹ããã³ããã使ãææ³ã¯ãåå¤åå²ãã¨ãå¢çå¤åæãã§ãããããã¯ãããã試ããªãã¨ãããªãå ¥åã大éã«ããç¶æ³ãç¾å®çãªæéã§å¯¾å¦ããããã«å ¥åãéå¼ãããã®æ¹æ³ã§ããåå¤åå²ã¯åºåãåãã«ãªãå ¥åãã代表å¤ãé¸ã¶ã¨ããæ¹æ³ã§å ¥åãéå¼ãã¾ãããå¢çå¤åæã§ã¯å é¨ã®æ¡ä»¶åå²ã®ã¡ããã©å¢ç®ä»è¿ãééããå ¥åã¯ãªãã¹ãéå¼ããªãæ¹æ³ã¨ãè¨ãæããããã§ãããã
ä»åã¯å³å¯ãªåå¤åå²ã¯ããããã£ããå°ããå¤ã¨å¤§ããªå¤ãã代表å¤ããã¹ãã±ã¼ã¹ã«å ããã¨ãã¾ããããã¤ãã§ã«å¢çå¤ã«ãªããã㪠0 ãå ¥ãã¦ããã¾ãï¼
describe('add', () => { [ {lhs: ONE, rhs: ONE, expected: TWO }, // å°ããå¤ã¨å°ããå¤ã®çµã¿åãã {lhs: ONE, rhs: ZERO, expected: ONE }, {lhs: ONE_MILLION, rhs: ONE, expected: ONE_MILLION_ONE }, // 大ããå¤ã¨å°ããå¤ã®çµã¿åãã {lhs: ONE, rhs: ONE_MILLION, expected: ONE_MILLION_ONE }, // å°ããå¤ã¨å¤§ããå¤ã®çµã¿åãã {lhs: ZERO, rhs: ZERO, expected: ZERO }, // å¢çå¤ã«ãªããããªå¤ ] .forEach(({lhs, rhs, expected}) => { context(`(${lhs}, ${rhs})`, () => { it(`should return ${expected}`, () => { const actual = add(lhs, rhs); assert.deepStrictEqual(actual, expected); }); }); }); });
ãã®ããã«è¶³ãã¾ããï¼ããã«æ éãªæ¹ãªãã°ãèªç¶æ°åã®æ大å¤ãå¢çå¤ã«ãªããããªã®ã§ãããå ããã§ãããï¼ãã®ä¾ã¯ç°¡åã«ããããã«æ大å¤ãè¨ãã¦ããªãï¼ã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ
ãã¦ãããã¾ã§æ¤æ»å¯¾è±¡ã®å ¥åãåºãã¦ãã¾ãããããããªãå®å¿ã§ããã§ããããï¼ä»¥åã®ç§ã§ããã°ãã®ããããç¾å®çãªå®å¿ã®ã©ã¤ã³ã¨ãã¦æãæ¢ãã¦ãã¾ãããå®ã¯ãã®å¤æã¯ã大æµã®ãã°ã¯å ¥å空éã®å°ããé¨åãæ¢ãã ãã§è¦ã¤ãããã¨ããå°ã¹ã³ã¼ã仮説2ãæé»ã«ä»®å®ãã¦ãã¾ãããã®ä¾ã§ã¯ãã£ã½ã©å¦ãªå®è£ ãããªãéãã¯æãç«ã¤ã¨æãã¾ãããæ¤æ»ãã対象ã«ãã£ã¦ã¯æãç«ããªããã¨ãããã¾ãï¼ç¹ã«å¾è¿°ãã並åã·ã¹ãã ãªã©ï¼ãããã§ã¯èª¬æãç°¡åã«ä¿ã¤ããã«ããã®ä»®èª¬ã足ãç®ã§ãæãç«ããªãã¨ãã¦è©±ãé²ãã¾ãã
ã¨ãããã¨ã§ãå®å¿ã§ããããã«ãªãã¾ã§ãã¹ãã±ã¼ã¹æ°ãå¢ããã¦ããã¾ãããããã ãããããæã§è¿½å ãã¦ããã®ãå³ãããªã£ã¦ããã¯ãã§ãããã®ãããªæã«ãã¹ããã³ã使ãæ¹æ³ã¯ QuickCheck ã«ä»£è¡¨ããã Property-based Testing ã§ããProperty-based Testing ã§ã¯ããã¾ã§ã®ææ³ã¨ã¯ç°ãªãå ¥åãããã°ã©ããæ示ãã¾ããã代ããã«åãå¤ã®çæå¨ãå ¥åãèªåçã«å¤§éã«çæãã¦ããã¾ãã
ãªãã¦ä¾¿å©ãªãã ï¼ã¨æãããããã¾ããããå®ã¯ããã§èãæ¹ã®è»¢æãå¿ è¦ã«ãªãã¾ããä»ã¾ã§ã®ã³ã¼ããæãåºãã¦æ¬²ããã®ã§ãããèªåãã¹ãã§ã¯æå¾ ããåºåã¨å®éã®åºåã®æ¯è¼ã¨ããå½¢ã§è¨è¿°ãã¦ãã¾ããï¼
// ããã¾ã§ã®ã³ã¼ã describe('add', () => { context('when given 1 and 1', () => { it('should return 2', () => { const actual = add(ONE, ONE); // ããã°ã©ããå ¥åã¨ã㦠1, 1 ãé¸ã³ã const expected = TWO; // æå¾ ããåºåã¨ã㦠2 ãæå®ããã assert.deepStrictEqual(actual, expected); }); }); });
ããããå ¥åãèªåçæãããã®ã§ããã°æå¾ ããåºåãã©ã®ããã«æå®ããã°ããã®ã§ããããï¼
// Property-based Testing ã®ã³ã¼ã describe('add', () => { context('when given X and Y', () => { it('should return a result same as result of Y and X', () => { const [x, y] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(x, y); const expected = '???'; // æå¾ ããåºåã¨ã㦠??? ãæå®ããã assert.deepStrictEqual(actual, expected); }); }); });
ä½ã¨ãªãèãæ¹ã転æããªãã¨ãããªãé¨åãããã£ã¦ããã§ãããããProperty-based Testing ã§ã¯å
¥åã«å¯¾ããå
·ä½çãªæå¾
åºåãæå®ã§ããªãã®ã§ãã代ããã« å
¥åã¨åºåã®éã§æãç«ã¤é¢ä¿ãå©ç¨ãã¾ããä¾ãã°è¶³ãç®ã¯é åºãå¤ãã¦ãçµæãåãã¯ãï¼x + y = y + x
ï¼ã§ãããã次ã®ããã«å¼æ°ã®é åºãã²ã£ããè¿ãã¦ãçµæãåãã«ãªãã¨ãã£ãæå®ããã¾ãï¼
describe('add', () => { context('when given X and Y', () => { it('should return a result same as result of Y and X', () => { const [x, y] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(x, y); const expected = add(y, x); // é åºãå対ã«ãã¦ãè¨ç®çµæãå¤ãããªããã¨ã確ãããã assert.deepStrictEqual(actual, expected); }); // å®éã«ã¯ valuesGen ã®å¤ãå¤ãã¦å¤§éã«ç¹°ãè¿ãã }); });
ããã ãã ã¨å ¨ãä¸ååã§ãããã次ã®ããã«è¶³ãç®ã®æã¤æ§ã ãªå ¥åºåã®éã®é¢ä¿ã®æ¤è¨¼ã追å ãã¦ããã¾ãï¼
describe('add', () => { context('when given X and Y', () => { it('should return a result same as result of Y and X', () => { const [x, y] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(x, y); const expected = add(y, x); // å¼æ°ã®é åºãå対ã«ãã¦ãè¨ç®çµæãå¤ãããªããã¨ï¼äº¤ææ³åï¼ã確ãããã assert.deepStrictEqual(actual, expected); }); }); context('when given (X and Y) and Z', () => { it('should return a result same as result of X and (Y and Z)', () => { const [x, y, z] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(add(x, y), z); const expected = add(x, add(y, z)); // è¨ç®ããé åºãå¤ãã¦ãçµæãå¤ãããªããã¨ï¼çµåæ³åï¼ã確ãããã assert.deepStrictEqual(actual, expected); }); }); context('when given X and 0', () => { it('should return X', () => { const [x] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(x, ZERO); const expected = x; // 0 ã¨è¶³ãã¦ãå ã®æ°åã¨åãã«ãªããã¨ï¼åä½å ã®åå¨ï¼ã確ãããã assert.deepStrictEqual(actual, expected); }); }); context('when given X', () => { it('should return something not equal X itself', () => { const [x] = valuesGen(/* å¤ã®çæå¨ãèªåçã«ä½ããã®èªç¶æ°ãé¸ã¶ã®ã§ã*/); const actual = add(x, ONE); const unexpected = x; // 1ã足ãã°çµæã¯Xã¨ã¯ç°ãªããã¨ã確ãããã assert.deepStrictEqual(actual, expected); }); }); // å®éã«ã¯ valuesGen ã®å¤ãå¤ãã¦å¤§éã«ç¹°ãè¿ãã // åã® Parameterized Test ãæ®ãã¦ããã¨ããå®å¿ã });
ãã®ããã«ãã¦å ¥åãèªåçæããã°æã§æ¸ããæããããã£ã¨å¤ãã§ããããã§ããããããå¼·ãå®å¿ãå¾ãããããã§ãã
ãã ã代ããã«å¤±ããããã®ãããã¾ããParameterized Testã¾ã§ã¯å ·ä½çãªæå¾ ãæ¸ããããæ·±ãèããªãã¦ãããã£ãã®ã§ãããProperty-based Testing ã§ã¯å ·ä½çãªæå¾ ãæ¸ããªããªã£ãããã«ããæ½è±¡åº¦ã®é«ããå ¥åã¨åºåã®éã®é¢ä¿ããè¦æããã°ãªãã¾ãããããã«ã¯ä¸å®ã®è¨ç·´ãå¿ è¦ã§ãã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ â (å ¥åºåã®å ·ä½æ§ã®å£) â Property-based Testing
ãã¦ãå®ã¯ããã§ãã¾ã ãã¹ãã±ã¼ã¹ã¯å®å ¨ã§ã¯ããã¾ãããèªåçæãããå¤ã¯æã§ä½ãããããããã£ã¨å¤ãã§ãããããã§ãå ¥åå¯è½ãªå¤ï¼èªç¶æ°åã®å¤ãã¹ã¦ï¼ããã¯ãã£ã¨å°ãªãã®ã§ãããã ãèªç¶æ°ã®ä¾ã§ã¯åè¿°ã®å°ã¹ã³ã¼ã仮説ï¼å¤§æµã®ãã°ã¯å ¥å空éã®å°ããé¨åãæ¢ãã ãã§è¦ã¤ããï¼ãæãç«ã¤ã§ãããããããã£ã¨å ¥åãã¹ã¦ã®åä½ç¢ºèªã¯ä¸å¿ è¦ã«æããã§ãããããããå¾è¿°ãã並è¡ã·ã¹ãã ã§ã¯å°ã¹ã³ã¼ã仮説ãæãç«ããªããã¨ãå¤ãããããã£ã¦ç¶²ç¾ æ§ã¯ä¾ç¶ã¨ãã¦éè¦ãªã®ã§ãããã®ããããå°ãç¶²ç¾ æ§ã®è©±ãç¶ãã¾ãã
ãªããããã¾ã§ã®ææ³ã®å»¶é·ç·ä¸ã§å ¥åãç¶²ç¾ çã«æ±ãæ¹æ³ã¨ãã¦ãç¶²ç¾ çãªå ¥åãå¯è½ãªã¬ãã«ã¾ã§å ¥åå¯è½ãªå¤ã®æ°ãæ¸ããæ¹æ³ãããã¾ããèªç¶æ°ã®ä¾ã§ããã¨å©ç¨ãããæ大ã®èªç¶æ°ãããã¾ã§å¤§ãããªãã®ã§ããã°ãæ大å¤ãè¨ãã¦ããã¾ã§ã®å ¥åãã¹ã¦ãç¶²ç¾ çã«æ¤è¨¼ããæ¹æ³ãã¨ãã¾ãï¼ãã®èãæ¹ã¯å¾è¿°ãã並è¡ã·ã¹ãã ã§ãéè¦ï¼ãããã¾ã§ãã¦ãããããå¾æ¥ã®æ¹æ³ã®å»¶é·ç·ä¸ã§ãç¶²ç¾ çãªåä½ç¢ºèªãå¯è½ã«ãªãã¾ããã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ â (å ¥åºåã®å ·ä½æ§ã®å£) â Property-based Testing â (ç¶²ç¾ æ§ã®å£) â å¯è½ãªãå ¥å空éã®å¶é
ãã ããã®æ¹æ³ã¯å ¥åãçµããã¨ãã®ã¿ä½¿ããæ¹æ³ã ã£ããã¨ãæãåºãã¦ãã ãããä»æ§ã«ãã£ã¦ã¯ãããé©ç¨ã§ããªããã¨ãå¤ããç¹ã«ä¸¦è¡ã·ã¹ãã ã«ããã¦ã¯ãã®æ¹æ³ãã¨ã£ã¦ããªãå ¥å空éãåºãããå ´åãé »ç¹ã«ãããã¾ãã
ããã¦ãããããå ãããå½¢å¼ææ³ã®åãåããªãã¨ãããªãä¸çãªã®ã§ãã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ â (å ¥åºåã®å ·ä½æ§ã®å£) â Property-based Testing â (ç¶²ç¾ æ§ã®å£) â å¯è½ãªãå ¥å空éã®å¶é â (æ±ããå ¥å空éã®å¤§ããã®å£) â å½¢å¼ææ³ï¼ï¼ï¼ï¼ï¼
ç¶²ç¾ æ§ã¸ã®ææ¦
ããããå ã¯ãå½¢å¼ææ³ã®1ã¤ã§ããå®ç証ææ¯æ´ç³»ã使ã£ã¦åºãå ¥å空éãæ¤è¨¼ãã¦ã¿ã¾ããããä»å㯠Isabelle ã¨ããå®ç証ææ¯æ´ç³»ã®ã·ã¹ãã ãé§ä½¿ãã¦æ¤æ»ããã対象ã®å ¥åãã¹ã¦ã«å¯¾ãã¦æ§è³ªã確èªãã¾ãããã ããã®ããã«èª¬æããã¦ããªããªã飲ã¿è¾¼ããªãã¨æãã¾ãã®ã§ãããå°ãèªç¶æ°ã®ä¾ãç¶ãã¦ããã¾ãã
ãã¦ãä»åã® add
ã®å®è£
ã次ã®ããã ã£ãã¨ãã¾ãï¼
// add é¢æ°ã®å ¥åå¤ã¯ Zero ã¾ã㯠Succ ã®ãããããZero 㯠0 ãæå³ããSucc ã¯ãã©ã¡ã¼ã¿ã®èªç¶æ°ã +1 ããèªç¶æ°ã表ç¾ããã // ã¤ã¾ããnew Succ(new Zero()) 㯠0 + 1 ãªã®ã§ 1 ãæå³ããnew Succ(new Succ(new Zero())) 㯠(0 + 1) + 1 ãªã®ã§ 2 ãæå³ããã class Zero {} class Succ { constructor(nat) { this.v = nat } } function add(a, b) { // ãã b ã 0 ãªã a ãçµæï¼a + 0 = a ã¨ãããã¨ï¼ã if (b instanceof Zero) { return a; } // ãã b ã 0 ã§ãªããã° b ã® Succ åã®å¤ï¼b - 1ï¼ã¨ a ã«å¯¾ãã¦å帰çã« add ãå¼ã³åºãã¦ã // æå¾ã«å ¨ä½ã¨ã㦠+1 ããï¼ã¤ã¾ã (a + (b - 1)) + 1 = a + b ã¨ãããã¨ï¼ã // ããããã¨ãæçµçã« b ã 0 ã«ãªãã¾ã§å帰çã« add ãç¹°ãè¿ãããb ã 0 ã«ãªã£ãæç¹ã® // çµæã§å帰ãåæ¢ã㦠b ã®èªç¶æ°ã®åæ°å +1 ãã¦å¤ãæ»ã£ã¦ããã return new Succ(add(a, b.v)); }
ããã¦ä¸ã® JavaScript ã®ã³ã¼ãã¯æ¬¡ã® Isabelle ã§ã®è¡¨ç¾ã¨å¯¾å¿ããã¨ãã¾ãããï¼=JavaScript ã®ã³ã¼ã㨠Isabelle ã®ã³ã¼ããã¾ã£ããåãæ¯ãèããããã¨ãã¦ãã¾ã3ï¼ï¼
(* JavaScript ã® Zero 㨠Succ ã®ã¯ã©ã¹ã«å¯¾å¿ããåã nat ã¨ãã¦å®ç¾©ããã *) datatype nat = Zero | Succ nat (* add 㯠JavaScript ã® add ã¨åãå帰çãªå®ç¾©ã¨ããã *) primrec add :: "nat =>> nat => nat" where "add a Zero = a" | "add a (Succ b) = Succ (add a b)"
Isabelle ã§ã¯ãã®ããã«è¨è¿°ãããå®ç¾©ã«å¯¾ãã¦ã証æããå¯è½ã§ããIsabelle ã§è¨è¿°ãããã³ã¼ãã¯ãæ°å¦ã®è¨¼æã®ããã«è«ççãªæ¨è«ã«ãã£ã¦çµæãã©ããªãããæ¨æ¸¬ã§ããããã§ãããªãããã®æ¹æ³ã§ã Property-based Testing ã¨åæ§ã«å ¥åºåã®éã§æãç«ã¤é¢ä¿ã使ãã¾ãã
ä¾ãã°ãåã® Property-based Testing ã§æ¤è¨¼ãã x + 0 = x
ã¯æ¬¡ã®ããã« Isabelle ã§è¨è¿°ã§ãããããä»åã¯å
¨èªåã§è¨¼æã§ãã¾ãï¼Isabelle ã¯èªåçãªè¨¼æã«åªãã¦ããï¼ï¼
(* ãã¹ã¦ã®èªç¶æ° x ã«ã¤ã㦠x + 0 = x ãæãç«ã¤ãã¨ã証æããã *) theorem "âx. add x Zero = x" by auto (* èªåã§ã®è¨¼æãæ示ï¼èªåã§è§£ããï¼ã *)
ãã®è¨¼æãæåããã¨ãããã¨ã¯ãã©ããªèªç¶æ° x
ã§ãã£ã¦ã x + 0 = x
ãæºãã ã¨ç¢ºèªã§ãããã¨ãæå³ãã¾ããããã§éè¦ãªã®ã¯ãã©ããªèªç¶æ°ã§ããã¨ããé¨åã§ãä»åã¯èªç¶æ°ã®å®ç¾©ã®ä¸éãä¸ãã¦ãã¾ããããã¨ã¦ã¤ããªã大ããªèªç¶æ°ã§ãã£ã¦ããããæãç«ã¤ã®ã§ã4ã
ãããããããããã§ã¯å®æã湧ããªãã¨æãã®ã§ã試ãã« add
ã®å®ç¾©ãããã¨ééãã¦ã©ããªãããè¦ã¦ã¿ã¾ãããï¼
primrec add :: "nat â nat â nat" where "add a Zero = Zero" (* ããã¨ééãã¦ã¿ã *) | "add a (Succ b) = Succ (add a b)"
ãã®ç¶æ
ã§ãå
ã»ã©ã® x + 0 = x
ã証æãããã¨ããã¨è¨¼æã¯å¤±æãã¾ãï¼
(* ãã¹ã¦ã®èªç¶æ° x ã«ã¤ã㦠x + 0 = x ãæãç«ã¤ãã¨ã証æããã *) theorem "âx. add x Zero = x" by auto (* èªåã§ã®è¨¼æãæ示ï¼å¤±æããï¼ã *) (* Isabelle ã®åºåï¼ theorem add_iden: ?x = add ?x Zero Failed to finish proofâ: goal (1 subgoal): 1. x = Zero *)
ããã¿ã㨠subgoal: x = 0
ã¨ããåºåã«ãªã£ã¦ãã¾ããããã¯ã©ããªèªç¶æ° x
ã«å¯¾ãã¦ã x = 0
ãæç«ãããªãä¸è¨ã®ééã£ãå®ç¾©ã§ã証æã§ãã㨠Isabelle ãæãã¦ããã¦ãã¾ããè¦ããã« x
ã 0, 1, 2, 3, ... ã®ãããã§ã x = 0
ãæç«ããã°è¨¼æã§ããã¨ãããã¨ã§ãããx
ã 0 以å¤ã«ã¤ãã¦ã¯ x = 0
ãæç«ããã¨ã¾ããããã§ããããã©ããã§ééããã¨ãããã®ã§ãããã®ããã« Isabelle ã¯è¨¼æããããã¨ãããè«ççãªæ¨è«ã«ãã£ã¦è¨¼æã§ãã極ãã¦å¼·åãªæ段ã¨ãªãã¾ãã
ã¾ãã次ã®ããã« x + 0 = x
ã®ä¾ä»¥å¤ã®æ§è³ªãã»ã¼èªåã§è¨¼æã§ãã¾ãï¼ä¸é¨ã¯äººéã®æã§è£é¡ãåãåºãã¦ãã³ããä¸ãã¦ããï¼ï¼
(* èªåæ¨è«ã®ããã®æããããä¸ããããã®è£é¡ã *) lemma add_iden [simp]: "x = add x Zero" by auto lemma add_assoc: "add (add x y) z = add x (add y z)" apply(induct_tac z) by auto lemma [simp]: "Succ (add x y) = add (Succ x) y" apply(induct_tac y) by auto lemma add_comm: "add x y = add y x" apply(induct_tac y) apply(auto) apply(induct_tac x) by auto (* å¼æ°ã®é åºãå対ã«ãã¦ãè¨ç®çµæãå¤ãããªããã¨ï¼äº¤ææ³åï¼ã確ãããã*) theorem "â x y. add x y = add y x" apply(intro allI) by (rule add_comm) (* è¨ç®ããé åºãå¤ãã¦ãçµæãå¤ãããªããã¨ï¼çµåæ³åï¼ã確ãããã*) theorem "â x y z. add (add x y) z = add x (add y z)" apply(intro allI) by (rule add_assoc)
ã¾ã¨ããã¨ãããã§ã¯å®ç証ææ¯æ´ç³»ã使ãã°å ¥å空éãå¶éã§ããªãç¶æ³ã§ãã£ã¦ãç¶²ç¾ çãªæ¤æ»ãã§ããã¨ãããã¾ããããªãããã以å¤ã®ä¾ã§ãããã¿ã¼ã³æ°ãå¤ãç¶æ³ã§ã Isabelle ã¯é«ãå¨åãçºæ®ã§ããã¨ç¥ããã¦ãã¾ãï¼ã±ãã©ã¼äºæ³ã®å½¢å¼è¨¼æã« Isabelle ã使ãããä¾ãåèã«ãªãï¼ã
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ â (å ¥åºåã®å ·ä½æ§ã®å£) â Property-based Testing â (ç¶²ç¾ æ§ã®å£) â å¯è½ãªãå ¥å空éã®å¶é â (æ±ããå ¥å空éã®å¤§ããã®å£) â å®ç証ææ¯æ´ç³»ã«ããå½¢å¼æ¤è¨¼
ç¾å®çãªä¾
ããã¾ã§ã®ä¾ã§ã¯ã説æãç°¡åã«ãããã極ãã¦åç´åãããéç¾å®çãªä¾ãæ±ã£ã¦ãã¾ãããããã§ããããã¯ç¾å®çã«å½¢å¼ææ³ãå¿ è¦ã«ãªãç¶æ³ã説æãã¦ããã¾ãã
ç§ãããã¾ã§æ©ãã§ããã®ã¯ãiOS ã¢ããªã Web ã¢ããªã«ããã¦å¤ç¨ããå調ãã¦åä½ããç¶æ æ©æ¢°ã®ãã°ãå¾æ¥ã®èªåãã¹ãã§è¦ã¤ããããªããã¨ã§ãããiOS ã¢ããªã«éãããä½ããç¶æ ããã¤ãªãã¸ã§ã¯ãã¯ç¶æ æ©æ¢°ã¨ãã¦è¨è¨ãã¦ããã¨ç¶æ ã®å¤§å±è¦³ã®ææ¡ã楽ã«ãªãã¾ãããã®ãããç¶æ æ©æ¢°ã¯é »åºã®è¨è¨ãã¿ã¼ã³ã¨ãªãã¾ãï¼å ·ä½çã«ã©ã®ãããªã³ã¼ãã«ãªãã㯠Kuniwak/reversi-ios ãåç §ï¼ããªãããããã®ç¶æ æ©æ¢°ã«ã¯ç¶æ ãå¤ãã£ããã¨ãç£è¦ã§ããã¤ãã³ãã¹ããªã¼ã ãç¨æãã¦ããã¦ãView ã¯ããããå¤æ´ãæ¤ç¥ãã¦è¦ãç®ãå¤æ´ããããã«æ§æãã¾ãã
ãã¦ããããåç´ãªç¶æ æ©æ¢°ãã 1ã¤ãªã話ã¯ç°¡åã§ãããåé¡ã¯ç¾å®çãªã¢ããªã¯å°ããªç¶æ æ©æ¢°1ã¤ã§ã¯è¡¨ç¾ã§ããªããããå°ããªç¶æ æ©æ¢°ãè¤æ°çµã¿åãããå¿ è¦ãããã¨ããç¹ã§ãï¼ãã®æ¹æ³ã¯ä¸è¬çã« Hierarchal Finite State Machine ã¨ãã¦ç¥ããã¦ããï¼ã
ä¸è¬ã«ããã®ãã㪠並ååä½ããç¶æ æ©æ¢°ã®çµã¿åããã®æ¤è¨¼ã«å¿ è¦ãªãã¹ãã±ã¼ã¹æ°ã¯äººéã®æ³åãè¶ ãã¦ãã¾ã ãä¾ãã°ã次ã®å³ã¯ã¨ããã¤ãã³ãã§å®è£ ããã¢ããªã®ç¶æ æ©æ¢°å ¨ä½ã®ç¶æ é·ç§»å³ã§ãï¼å ¨é¨è¼ãåããªãã®ã§ããä¸é¨ï¼ï¼
ï¼å ¨ä½ï¼
ãã®å³ãä¸è¦ããã ãã§ãProperty-based Testing ãå«ãå¾æ¥ã®ãããã®æ¹æ³ãã»ã¼ç¡åã ã¨ãããã¨æãã¾ãããªãããã®ä¸ã®ããããããªé¨åã«ãã°ãæ½ãã§ãã¦ãå®éã«ä»åã®ãªãã¼ã·ã¢ããªã§ãã¢ãã¡ã¼ã·ã§ã³ã«ä¸è²«æ§ã®ãªããã°ãå¾ããè¦ã¤ããã¾ããããã®åå ã¯ã¤ãã³ãã¹ããªã¼ã ã®è³¼èªè ã2ã¤ãããã¨ã«æ°ã¥ãã¦ããããããè³¼èªè ã®å¼ã³åºãé åºãæå¾ ã¨éã£ã¦ãããã¨ãåå ã§ããï¼ãã®å³ã®ä¸ã®ããããã®é·ç§»ã«æ³å®å¤ã®é·ç§»ããã£ã1ã¤ãã£ãã®ãåå ï¼ã
ãã®è©±ãä¸è¬åããã¨ããããã«ãã¹ã¬ããããã°ã©ãã³ã°ã®éçºãé£ããã¨è¨ãããã®ã¯ããã®è¨å¤§ãªæ°ã®çµã¿åããã®ãªãã®ããããããªé¨åã«ãããããã¯ãç¡éã«ã¼ããªã©ã®æ¬ é¥ãæ½ãã§ãããã¨ã«äººéãæ°ã¥ããªãããã§ããããã¦ãããã¾ã§è¦ã¦ããããã«ãè¨å¤§ã®å ¥åã®çµã¿åããæ°ãããã¨ãèªåãã¹ããå«ãåçæ¤æ»ã¯ç¡åã§ããã ããå½¢å¼ææ³ãéè¦ã«ãªãã®ã§ãã
ãªãä¸è¨ã®ã¢ããªã«ã¤ãã¦ã¯ãä»åç´¹ä»ããå®ç証ææ¯æ´ç³»ã¨ã¯å¥ã®å½¢å¼ææ³ã§ãããã¢ãã«æ¤æ»5ãã試ã¿ã¾ããï¼è©³ç´°ï¼ãã¢ãã«æ¤æ»ã¯ä¸¦åã·ã¹ãã ã®ç¶²ç¾ çãªæ¤è¨¼ãå¾æã¨ãã¦ãã¦ãç§ã®æ©ã¿ã解決ã§ããæåãªæ段ã®1ã¤ã§ãããã®ã¢ãã«æ¤æ»ã巨大ãªç¶æ é·ç§»ã°ã©ããæ±ãéã«ã¯å ·ä½çãªå ¥åºåãæ示ã§ããªããããããã¾ã§åæ§ã«æ½è±¡çã«ãã®ãã¨ãæããªããã°ãªããªãç¹ãå ±éãã¦ãã¾ããã¡ãªã¿ã«ã¢ãã«æ¤æ»ã¯æ¬¡ãããã®ä½ç½®ä»ãã§ãï¼
- ããã¾ã§ã®æµã
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å â Parameterized Test â åå¤åå²ã»å¢çå¤åæ â (å ¥åºåã®å ·ä½æ§ã®å£) â Property-based Testing â (ç¶²ç¾ æ§ã®å£) â å¯è½ãªãå ¥å空éã®å¶é â ã¢ãã«æ¤æ» â (æ±ããå ¥å空éã®å¤§ããã®å£) â å®ç証ææ¯æ´ç³»ã«ããå½¢å¼æ¤è¨¼
ãã¹ãã±ã¼ã¹ã®å¢å ã«ã¤ãèµ·ãã£ããã¨
ããã¾ã§ã®æµããå°ãæ¯ãè¿ãã¾ããããèªç¶æ°ã®è¶³ãç®ãä¾ã«ãã¹ãã±ã¼ã¹ã®æ°ãå¢ããã«ã¤ã次ã®ç®æ¡æ¸ããªã¹ãã®ä¸ã®æ¹ã¸ææ³ã移ãå¤ãã£ã¦ããã¨ãè¦ã¦ãã¾ããï¼
- åæ¡ä»¶ã®ãã¹ãã±ã¼ã¹è¿½å
- Parameterized Test
- åå¤åå²ã»å¢çå¤åæ
- ââ(å ¥åºåã®å ·ä½æ§ã®å£)ââ
- Property-based Testing
- ââ(ç¶²ç¾ æ§ã®å£)ââ
- å¯è½ãªãå ¥å空éã®å¶é
- ã¢ãã«æ¤æ»
- ââ(æ±ããå ¥å空éã®å¤§ããã®å£)ââ
- å®ç証ææ¯æ´ç³»ã«ããå½¢å¼æ¤è¨¼
è¦ããã«ãä¸ã®æ¹ã®æ段ã§ããå½¢å¼ææ³ï¼8ã¨10ï¼ã¯è¨å¤§ãªéã®ãã¹ãã±ã¼ã¹ãç¾å®çãªè¨è¿°éã§è¡¨ç¾ããããã®æ¹æ³ã§ãããã®ããæ½è±¡åº¦ãä¸ãã£ã¦ãã¾ãæãã¥ãããªã£ã¦ãã¾ãã¨ãããã¨ãªã®ã§ãããã
ãã®ãããªäºæ ãç¸ã¾ã£ã¦ãå½¢å¼ææ³ãä¸æã«æ±ãã®ã«ã¯ããªãã®ç¥èãå¿ è¦ã§ããå®éã«åãçµãã§ã¿ãã¨ãããã®ã§ãããã¾ã人éã¯æå³éãã®è«çå¼ãã¢ãã«ãæ¸ãã¾ããï¼å¿ è¦ãªæ¡ä»¶ãå¿ãã¦ãããããããæå³ãééã£ã¦ããããï¼ãå½ããåã®è©±ã§ãããå¾æ¥ã®ã³ã¼ãã§ããæ£ããæ¸ããªãã®ã«ãããæ½è±¡åº¦ã®é«ãè«çå¼ãã¢ãã«ãæåããæ£ããæ¸ããã¯ãããªãã®ã§ãã
ãããã£ã¦å½¢å¼ææ³ã«ããã¦ãèªåã®è¨è¿°ããã¢ãã«ãè«çå¼ãèªåã®æå³éãã«ãªã£ã¦ããã確ãããä½æ¥ã¯é¿ãã¦éãã¾ãããã ãããããIsabelle ãä»ã®å½¢å¼ææ³ç³»ã®ãã¼ã«ãä½ãè¨ã£ã¦ããã®ããç解ããããã®æ°çè«çå¦ã®å¦ç¿ãåºç¤çè«ã¸ã®ç解ãã¨ã¦ãéè¦ã«ãªãã¾ããããã«ããã®ãããªç¥èã¨ã¯å¥ã« TDD ã®ããã«è«çå¼ãã¢ãã«ããã¾ãã«ç¢ºèªã§ããããæºåãã¦ããã¨ãã£ãé²ãæ¹ã®ãã¦ãã¦ãéè¦ã«ãªãã¾ãï¼ãã¦ãã¦ã®ä¾ï¼ã
ç§ãã¾ã ã¾ã ç¥èã¯è¶³ããªãã§ããã以åã¨ã¯ç°ãªãä»ã¯æ¬¡ã®ã¹ããããè¦ããããã«ãªãã¾ããããã¨ã¯ä¸æ©ãã¤é²ãã§ãã ãã ã¨æã£ã¦ãã¦ãä»ãå½¢å¼ææ³ãå¦ã³ã¤ã¤å®è·µã«åãçµãã§ãã¾ãã
ã¾ã¨ã
ãã®è¨äºã§ã¯ã以ä¸ã®3ç¹ã説æãã¾ããï¼
- ãã¹ãã±ã¼ã¹ã®å¢å ã«ã¤ãå¾æ¥ã®èªåãã¹ãã«éçã訪ãã
- ç¾å®ã®è¨è¨ã§é »åºããç¶æ æ©æ¢°ã®åæã¯ãã®éçãè¶ ãã¦ãã
- ããã«å¯¾å¿ã§ããæ段ãå½¢å¼ææ³ã§ãã
ãã®è¨äºããã£ããã«ãç§ã®ããã«å½¢å¼ææ³ã«èå³ããã¤ãã¹ããã³ãå¢ããã¨ãããªããã¨æã£ã¦ãã¾ãã
-
å®éã¯1ã¤ã®ãã¹ãã±ã¼ã¹ã§è¤æ°ã®å ¥åãé£ç¶ãã¦è©¦ãã³ã¼ããå¤ãè¦åãããã¾ããããã㯠Eager Testã¨å¼ã°ããã¢ã³ããã¿ã¼ã³ã§ããããã«ã¯2ã¤ã®åé¡ãããã¾ãã1ã¤ãã®åé¡ã¯ãã¹ãã±ã¼ã¹ã®æåã®æ¹ã§ assertion ã失æããã¨å¾ç¶ã®æ¤è¨¼ãå®è¡ãããããã¹ã失æã®æ å ±éãå°ãªããªãã¨ãããã®ã§ãã2ã¤ãã¯ãè¤æ°ã®å ¥åã1ã¤ã®ãã¹ãã±ã¼ã¹ã§ã¾ã¨ãã¦ãã¾ãã¨ãã¹ãã±ã¼ã¹ã®ååãææ§ã«ãªãã¾ãï¼ãã¹ãã®æå³ãæ¨æ¸¬ããä¸ã§éè¦ãªæ å ±ã失ãããï¼ããããã®åé¡ãé¿ããããããã®è¨äºã®ããã«1ã¤ã®è©¦ãããå ¥åã«å¯¾ãã¦1ã¤ã®ãã¹ãã¼ã±ã¼ã¹ã対å¿ããããã«ãã¾ãããã↩
-
Andoni, Alexandr; Daniliuc, Dumitru; Khurshid, Sarfraz; Marinov, Darko (2002). “Evaluating the small scope hypothesis”↩
-
ããã§å³å¯ãªå¯¾å¿ã¸ã®è¨åãé¿ããã®ã¯ JavaScript ã®å½¢å¼åãããæå³è«ãå¿ è¦ã ããã§ããæå³è«ãå½¢å¼çã«å®ããããå¦çç³»ï¼ä¾ãã° KJSï¼ä»¥å¤ã§ã¯ãIsabelle ã§ã®è¡¨ç¾ã¨æ¬å½ã«å¯¾å¿ãã¦ããã®ãã©ãããæ¤è¨¼ï¼æ£å½æ§è¨¼æï¼ããã®ã¯ã¨ã¦ã大å¤ã§ãã↩
-
å ã® JavaScript ã®ã³ã¼ãã¯ã»ã¨ãã©ã®å¦ç系㧠1000 ç¨åº¦ã®èªç¶æ°ã§ stack overflow ã§ã¨ã©ã¼ã«ãªãã¾ãï¼æ¬å½ã¯æ«å°¾å帰æé©åå¯è½ãªå½¢ã«ãããã£ããã§ãã証æã§æéåã£ãã®ã§è«¦ããâ¦ï¼ãéè¦ãªã®ã¯ JavaScript ã®ã³ã¼ã㨠Isabelle ã®ã³ã¼ãã®å¯¾å¿é¢ä¿ã§ããã®ããã«å帰ãæ·±ããªãå ´åã«å¯¾å¿é¢ä¿ãå´©ãããã証æã®çµæã¨å®éã® JavaScript ã§ã®å®è¡çµæãä¸è´ãã¾ããããããããå«ããæ¤è¨¼ãããããã°ããã®ãã㪠JavaScript ã®æ¯ãèããå½¢å¼çã«å®ç¾©ããæå³è«ã«è¸ã¿è¾¼ãå¿ è¦ãããã¾ãããä»åã¯èª¬æãç°¡åã«ããããã«ãããé¿ãã¦ãã¾ãã↩
-
ã¢ãã«æ¤æ»ã®å®ç¾©ã説æããã®ã¯ã¨ã¦ã大å¤ãªã®ã§ãå®ç¾©ãç¥ãããæ¹ã¯ãã¢ãã«æ¤æ»å ¥éããªã©ãèªãã¨ããããããã¾ããã↩