{"id":170,"date":"2024-05-21T17:48:48","date_gmt":"2024-05-21T20:48:48","guid":{"rendered":"https:\/\/springmasteryhub.com\/?p=170"},"modified":"2024-05-21T17:48:48","modified_gmt":"2024-05-21T20:48:48","slug":"specification-based-testing-devise-test-cases","status":"publish","type":"post","link":"https:\/\/springmasteryhub.com\/?p=170","title":{"rendered":"Specification-Based Testing: Devise test cases"},"content":{"rendered":"\n<p>This is the last part of the specification-based testing series. Now we are going to put all of the knowledge that we gained from the other steps and start creating our tests efficiently.<\/p>\n\n\n\n<p>If you followed every step, you already have questioned and prepared the scenarios that will help catch as many faults in your code and make sure everything is working as planned.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Let\u2019s recap:<\/h2>\n\n\n\n<p>This is the code that we are looking forward to testing (ADD with carry flag, 8XY4 opcode from the CHIP-8 emulator):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ 8XY4\n\/\/ ADD\nint registerxIndex = ((instruction &amp; 0x0F00) &gt;&gt; 8);\nint registeryIndex = ((instruction &amp; 0x00F0) &gt;&gt; 4);\n\nint firstToSum = registers&#x5B;registerxIndex];\nint secondRegisterToSum = registers&#x5B;registeryIndex];\n\nint registersSum = (firstToSum + secondRegisterToSum);\nregisters&#x5B;registerxIndex] = registersSum &amp; 0xFF;\nif (registersSum &gt; 255) registers&#x5B;registers.length - 1] = 1;\nelse registers&#x5B;registers.length - 1] = 0;\npc += 2;\n<\/pre><\/div>\n\n\n<p>To make it easier to devise the tests, I\u2019ll isolate this part of the code and put it in a separate class and method to make it easy to exemplify. In the real project, this is part of a CPU class that has the registers array, the program counter, etc, and a decode function to decode the instructions coming from RAM (I\u2019ll be showing the process of creating an emulator in the future in this blog).<\/p>\n\n\n\n<p>Here\u2019s the simplified version of the code we are going to test:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic class AddWithCarry {\n\n    private int&#x5B;] registers = new int&#x5B;16];\n    private int pc = 0;\n\n    public void addWithCarry(int instruction) {\n\n        if( ((instruction &amp; 0xF000)&gt;&gt;12) == 8 &amp;&amp; (instruction &amp; 0x000F) == 4) {\n            int registerxIndex = ((instruction &amp; 0x0F00) &gt;&gt; 8);\n            int registeryIndex = ((instruction &amp; 0x00F0) &gt;&gt; 4);\n\n            int firstToSum = registers&#x5B;registerxIndex];\n            int secondRegisterToSum = registers&#x5B;registeryIndex];\n\n            int registersSum = (firstToSum + secondRegisterToSum);\n            registers&#x5B;registerxIndex] = registersSum &amp; 0xFF;\n            if (registersSum &gt; 255) registers&#x5B;registers.length - 1] = 1;\n            else registers&#x5B;registers.length - 1] = 0;\n            pc += 2;\n        }\n    }\n\n    public void setRegister(int position, int value) {\n        this.registers&#x5B;position] = value;\n    }\n\n    public int getPc() {\n        return pc;\n    }\n}\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Step 1: Understanding the requirements<\/h3>\n\n\n\n<p>As we discussed at this step you\u2019ll use the specification to come up with our first scenarios. By doing that we already figure out some scenarios that we can create to make sure that our code follows the behavior specified. This is mostly the successful cases.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Scenario 1 &#8211; Sum without carry:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Store a value in a register X (120&nbsp;for&nbsp;example).<\/li>\n\n\n\n<li>Store&nbsp;a value in a register Y (10&nbsp;for&nbsp;example).<\/li>\n\n\n\n<li>The two values sum must not be higher than 255.<\/li>\n\n\n\n<li>Set the program counter to 0.<\/li>\n\n\n\n<li>Check if the sum result value in the register X is correct (in this&nbsp;scenario&nbsp;the sum will be 130).<\/li>\n\n\n\n<li>Check if the carry flag is 0.<\/li>\n\n\n\n<li>Check if&nbsp;the register Y was not changed.<\/li>\n\n\n\n<li>Check if the program counter was incremented by two.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Scenario 2 &#8211; Sum with carry:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Store a value in a register X (235, for example).<\/li>\n\n\n\n<li>Store a value in a register Y (30, for example).<\/li>\n\n\n\n<li>Set the program counter to 0.<\/li>\n\n\n\n<li>The two values sum must be higher than 255.<\/li>\n\n\n\n<li>Check if the sum result value in the register X is correct (9 in this example). Since&nbsp;we had an overflow of the 255 max value, we store only the 8-bit part, since&nbsp;265 is a 9-bit number (100001001), we store only the 8-bit part in X&nbsp;which&nbsp;will be 00001001 = 9.<\/li>\n\n\n\n<li>The 9th bit that overflows will&nbsp;be set&nbsp;in the carry flag.<\/li>\n\n\n\n<li>Check if the carry flag is 1.<\/li>\n\n\n\n<li>Check if&nbsp;the register Y was not changed.<\/li>\n\n\n\n<li>Check if the program counter was incremented by two.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Scenario 3 &#8211; The other registers cant affect X and Y:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Store 0 in X and Y.<\/li>\n\n\n\n<li>Store values in registers that are not X and Y.<\/li>\n\n\n\n<li>Set the program counter to 0.<\/li>\n\n\n\n<li>Check if the X remains 0.<\/li>\n\n\n\n<li>Check if Y remains 0.<\/li>\n\n\n\n<li>Check if the carry is 0.<\/li>\n\n\n\n<li>Check if the program counter was updated by two.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Explore the program<\/h3>\n\n\n\n<p>In the second step, we read the code. So we explored the program we found some answers about our code. The second step is for you to understand the requirements and specifications by reverse engineering your code, so you can come up with some scenarios as described above.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Explore partitions<\/h3>\n\n\n\n<p>In the third step, we identify some scenarios that could break our code. Some possible unexpected behaviors. The key here is to focus on what\u2019s possible to happen so we avoid over-testing scenarios that could never happen.<\/p>\n\n\n\n<p>In this step, we found some possible unexpected inputs like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Scenario 1 &#8211; The instruction can be 0:\n<ul class=\"wp-block-list\">\n<li>Set instruction to 0.<\/li>\n\n\n\n<li>Check if register X has not changed.<\/li>\n\n\n\n<li>Check if register Y has not changed.<\/li>\n\n\n\n<li>Check if the program counter has not changed.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Scenario 2 &#8211; Invalid instruction:\n<ul class=\"wp-block-list\">\n<li>Set instruction to an invalid value.<\/li>\n\n\n\n<li>Check if register X has not changed.<\/li>\n\n\n\n<li>Check if register Y has not changed.<\/li>\n\n\n\n<li>Check if the program counter did not change<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>In this step, we could pick some more scenarios, but to keep it short, I\u2019ll keep these examples based only on the instruction partition. But make sure to create tests for all the other partitions of your code that can assume the expected value.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Analyze boundaries<\/h3>\n\n\n\n<p>Last but not least, we get the scenarios we found checking the boundaries, we look at parts where one simple mistake can cause a bug with some specific values. And we found these scenarios:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Scenario 1 -Test the exact boundary value:\n<ul class=\"wp-block-list\">\n<li>in this scenario, since we are looking at a sum, we can make that the sum of X and Y will be exactly 255.<\/li>\n\n\n\n<li>Check if the carry is 0.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Scenario 2 &#8211; The boundary minus one:\n<ul class=\"wp-block-list\">\n<li>in this scenario, since we are looking at a sum, we can make that the sum of X and Y will be exactly 254.<\/li>\n\n\n\n<li>Check if the carry is 0.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Scenario 3 &#8211; The boundary plus one:\n<ul class=\"wp-block-list\">\n<li>in this scenario, since we are looking at a sum, we can make that the sum of X and Y will be exactly 256.<\/li>\n\n\n\n<li>Check if the carry is 1.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Devise test cases<\/h3>\n\n\n\n<p>Now we implement the scenarios that we came up with by doing the other steps of the specification-based techniques:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage org.example;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.*;\n\npublic class AddWithCarryTest {\n\n    @Test\n    public void testSumWithoutCarry() {\n        \/\/ Scenario 1: Sum without carry\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 120); \/\/ Register X\n        addWithCarry.setRegister(2, 10);  \/\/ Register Y\n        int instruction = 0x8124;         \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(130, addWithCarry.getRegisterValue(1));\n        assertEquals(0, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 0\n        assertEquals(10, addWithCarry.getRegisterValue(2)); \/\/ Register Y should not change\n        assertEquals(2, addWithCarry.getPc());\n    }\n\n    @Test\n    public void testSumWithCarry() {\n        \/\/ Scenario 2: Sum with carry\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 235); \/\/ Register X\n        addWithCarry.setRegister(2, 30);  \/\/ Register Y\n        int instruction = 0x8124;         \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(9, addWithCarry.getRegisterValue(1));  \/\/ 235 + 30 = 265, only 8-bit part stored\n        assertEquals(1, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 1\n        assertEquals(30, addWithCarry.getRegisterValue(2)); \/\/ Register Y should not change\n        assertEquals(2, addWithCarry.getPc());\n    }\n\n    @Test\n    public void testOtherRegistersUnaffected() {\n        \/\/ Scenario 3: Other registers don't affect X and Y\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 0);   \/\/ Register X\n        addWithCarry.setRegister(2, 0);   \/\/ Register Y\n        addWithCarry.setRegister(3, 50);  \/\/ Another register\n        int instruction = 0x8124;         \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(0, addWithCarry.getRegisterValue(1));\n        assertEquals(0, addWithCarry.getRegisterValue(2));\n        assertEquals(50, addWithCarry.getRegisterValue(3)); \/\/ Other registers should not change\n        assertEquals(0, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 0\n        assertEquals(2, addWithCarry.getPc());\n    }\n\n    @Test\n    public void testZeroInstruction() {\n        \/\/ Invalid scenario: instruction is 0\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 50);\n        addWithCarry.setRegister(2, 20);\n        int instruction = 0x0000; \/\/ Invalid instruction\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(50, addWithCarry.getRegisterValue(1));\n        assertEquals(20, addWithCarry.getRegisterValue(2));\n        assertEquals(0, addWithCarry.getPc()); \/\/ PC should not change\n    }\n\n    @Test\n    public void testInvalidInstruction() {\n        \/\/ Invalid scenario: instruction is not added with carry\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 50);\n        addWithCarry.setRegister(2, 20);\n        int instruction = 0x9123; \/\/ Invalid instruction for add with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(50, addWithCarry.getRegisterValue(1));\n        assertEquals(20, addWithCarry.getRegisterValue(2));\n        assertEquals(0, addWithCarry.getPc()); \/\/ PC should not change\n    }\n\n    @Test\n    public void testExactBoundary() {\n        \/\/ Boundary scenario: exact 255 sum\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 200);\n        addWithCarry.setRegister(2, 55);\n        int instruction = 0x8124; \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(255, addWithCarry.getRegisterValue(1));\n        assertEquals(0, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 0\n        assertEquals(2, addWithCarry.getPc());\n    }\n\n    @Test\n    public void testBoundaryMinusOne() {\n        \/\/ Boundary scenario: sum 254\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 200);\n        addWithCarry.setRegister(2, 54);\n        int instruction = 0x8124; \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(254, addWithCarry.getRegisterValue(1));\n        assertEquals(0, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 0\n        assertEquals(2, addWithCarry.getPc());\n    }\n\n    @Test\n    public void testBoundaryPlusOne() {\n        \/\/ Boundary scenario: sum 256\n        AddWithCarry addWithCarry = new AddWithCarry();\n        addWithCarry.setRegister(1, 200);\n        addWithCarry.setRegister(2, 56);\n        int instruction = 0x8124; \/\/ Add register Y to register X with carry\n\n        addWithCarry.addWithCarry(instruction);\n\n        assertEquals(0, addWithCarry.getRegisterValue(1));  \/\/ 256 wraps around to 0\n        assertEquals(1, addWithCarry.getRegisterValue(15)); \/\/ Carry flag should be 1\n        assertEquals(2, addWithCarry.getPc());\n    }\n}\n<\/pre><\/div>\n\n\n<p>And that\u2019s it! Now you have a good amount of scenarios that will help you guarantee the proper behavior of your code according to what was specified.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Want to know more about this topic?<\/strong><\/h3>\n\n\n\n<p>If you didn\u2019t read read the other articles of this series:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/springmasteryhub.com\/2024\/05\/14\/specification-based-testing-a-developers-secret-weapont\/\">Specification-Based Testing: A Developer\u2019s Secret\u00a0Weapon<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/springmasteryhub.com\/2024\/05\/15\/specification-based-testing-understand-the-requirements\/\">Specification-based Testing: Understand the\u00a0requirements<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/springmasteryhub.com\/2024\/05\/16\/specification-based-testing-explore-the-program\/\">Specification-based Testing: Explore the program<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/springmasteryhub.com\/2024\/05\/17\/specification-based-testing-exploring-partitions\/\">Specification-Based Testing: Exploring partitions<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/springmasteryhub.com\/2024\/05\/20\/specification-based-testing-analyze-boundaries\/\">Specification-Based Testing: Analyze boundaries<\/a><\/li>\n<\/ul>\n\n\n\n<p>In the following days, I\u2019ll be talking about structural-based tests. Learn how to look at your code structure to come up with some test scenarios!<\/p>\n\n\n\n<p>Stay tuned to learn more! Don&#8217;t miss out!<\/p>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/WillianFMoya\">Willian Moya (@WillianFMoya) \/ X (twitter.com)<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www.linkedin.com\/in\/willianmoya\/\">Willian Ferreira Moya | LinkedIn<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the last part of the specification-based testing series. Now we are going to put all of the knowledge that we gained from the other steps and start creating our tests efficiently. If you followed every step, you already have questioned and prepared the scenarios that will help catch as many faults in your [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[2],"tags":[13,18,20,25,27],"class_list":["post-170","post","type-post","status-publish","format-standard","hentry","category-best-pratices","tag-java","tag-programming","tag-software-development","tag-tdd","tag-testing"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=\/wp\/v2\/posts\/170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=170"}],"version-history":[{"count":0,"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=\/wp\/v2\/posts\/170\/revisions"}],"wp:attachment":[{"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/springmasteryhub.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}