Midterm Code - KU-SKE17/Software-Process GitHub Wiki

JUnit

create src/test/java/CalculatorTest.java

// add auto, after use @Before, @Test
import org.junit.Before;
import org.junit.Test;

// TODO: add
import static org.junit.Assert.*;

public class CalculatorTest {

    /**
    * Objects under test
    */
    private Calculator calculator;

    // TOL to number testing
    static final double TOL = 1.0E-4;

    /**
     * Initializes some calculators to test
     */
    @Before
    public void setUp() {
        calculator = new Calculator(10, 5);
    }

    @Test
    public void testSting() {
        assertEquals(calculator.toString(), "x = 10, y = 5");
    }

    @Test
    public void testAdding() {
        assertEquals(calculator.add(), 15, TOL);
    }
}

build.gradle

test {
    // TODO: comment
    // useJUnitPlatform()

    // TODO: add (no need)
    testLogging.showStandardStreams = true
}

Code Coverage

  1. Use intelliJ Coverage

    • go to testing file
    • right click: More Run/Debug
    • Run with Coverage
  2. Use JaCoCo

    • add apply plugin: 'jacoco' to build.gradle
    • go to Gradle tap
    • run build/build
    • run verification/test
    • run verification/jacocoTestReport
    • open build/report/jacoco/test/html/index.html

Mockito

build.gradle

dependencies {
    // TODO: add
    testImplementation 'org.mockito:mockito-inline:3.+'
    testImplementation 'org.mockito:mockito-junit-jupiter:3.+'
}

Dummy

  1. *Use Mockito.mock(class)

    CalculatorTest.java

    // TODO: add
    import org.mockito.Mockito;
    
    public class CalculatorTest {
    
        private Calculator calculator;
    
        @Before
        public void setUp() {
            // Mockito
            calculator = Mockito.mock(Calculator.class);
        }
    }
  2. Use @Mock and initMocks (MockitoAnnotations)

    CalculatorTest.java

    // add auto, after use @Mock
    import org.mockito.Mock;
    // add auto, after find/call MockitoAnnotations
    import org.mockito.MockitoAnnotations;
    
    public class CalculatorTest {
    
        // TODO: add @Mock
        @Mock
        private Calculator calculator;
    
        @Before
        public void setUp() {
            // Mockito
            MockitoAnnotations.initMocks(this);
        }
    }

Define method called [when, thenReturn]

// TODO: add (to use when, then)
import static org.mockito.Mockito.*;

// define method called
when(calculator.toString()).thenReturn("x = 5, y = 10");
when(calculator.add()).thenReturn(15);

// check assert
assertEquals(calculator.toString(), "x = 5, y = 10");

Define method called [when, thenAnswer]

 when(mock.someMethod(anyString())).thenAnswer(
     new Answer() {
         public Object answer(InvocationOnMock invocation) {
             Object[] args = invocation.getArguments();
             Object mock = invocation.getMock();
             return "called with arguments: " + Arrays.toString(args);
         }
 });

 // following prints "called with arguments: [foo]"
 System.out.println(mock.someMethod("foo"));

Check method called [verify]

// verify(MockObject, TIME).METHOD;
// TIME => times(int), atLeast(int), atMost(int), atLeastOnce(), never()
verify(calculator).add();               // exactly once
verify(calculator, times(2)).add();     // exactly 2 times
verify(calculator, atLeast(2)).add();   // at least 2 times

Stub

// Mockito#1 List
List<String> mockList = (List<String>) mock(List.class);
mockList.add("Apple"); // เรียกได้ แต่จะแก้ไม่ได้

// ทำให้ต้องมาเขียนเอง
when(mockList.get(anyInt())).thenReturn("Banana", "Apple");

System.out.println(mockList.get(0));    // "Banana"
System.out.println(mockList.get(1));    // "Apple"
System.out.println(mockList.get(2));    // "Apple"

Spy

// 1. ต้องมีของจริงก่อน
List<String> realList = new ArrayList<String>();
realList.add("Apple");
realList.add("Banana");
realList.add("Peter");

// 2. Mockito.spy(obj) จะ monitorของจริงได้ แก้ตัวเองได้ แก้ของจริงไม่ได้
List<String> spyList = Mockito.spy(realList);
spyList.add("Gift");

// when(spyList.get(anyInt())).thenReturn("Banana");

System.out.println(spyList.get(0));     // "Apple"  -> "Banana"
System.out.println(spyList.get(1));     // "Banana" -> "Banana"
System.out.println(spyList.get(2));     // "Peter"  -> "Banana"
System.out.println(spyList.get(3));     // "Gift"   -> "Banana"
System.out.println(spyList.get(-1));    // error!   -> "Banana"
System.out.println(spyList.get(5));     // error!   -> "Banana"

System.out.println(realList.get(0));    // "Apple"
System.out.println(realList.get(1));    // "Banana"
System.out.println(realList.get(2));    // "Peter"
System.out.println(realList.get(3));    // error!

ArgumentMatchers Static Methods

Method matches
any() match anything, including null
any(Class) match any arg of type T, not null
anyBoolean() boolean or non-null Boolean
anyDouble() double or non-null Double
anyCollection() any non-null Collection
anyCollectionOf(Class clazz) collection of type T
anyList(Class clazz) any non-null List
argThat(matcher) custom ArgumentMatcher
intThat(matcher) custom matcher for int argument
doubleThat(matcher) custom ArgumentMatcher
eq(value) argument equals value
contains(String substring) String argument containing substring
endsWith(String suffix) String argument ending with suffix
matches(String regex) String matches a regular expression
startsWith(String prefix) String argument starting with prefix

Cucumber

build.gradle

dependencies {
    // TODO: add
    testImplementation 'io.cucumber:cucumber-java:6.10.4'
    testImplementation 'io.cucumber:cucumber-junit:6.10.4'
}

// TODO: add
configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

// TODO: add
task cucumber() {
    dependsOn assemble, testClasses
    doLast {
        javaexec {
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            // TODO: edit args[3] to the project package (path after src/main/java)
            args = ['--plugin', 'pretty', '--glue', '', 'src/test/resources']
            // other args = ['--snippets', 'camelcase']
        }
    }
}

create src/test/resources/features/adding_number.feature

Feature: Add numbers

  Scenario: add numbers
    Given I have calculator of 2 and 5
    When I call add method
    Then I get 7.0

  Scenario: add same number
    Given I have calculator of 2 and 2
    When I call add method
    Then I get 4.0

  Scenario: add negative number
    Given I have calculator of -2 and 5
    When I call add method
    Then I get 3.0

create src/test/resources/cucumber.properties

cucumber.publish.quiet=true

go to Gradle tap: run other/cucumber

CalculatorTest.java

// add auto, after use @Given, @When, @Then, @Before
import io.cucumber.java.en.*;

// TODO: paste code from gradle terminal
// TODO: edit the code
⚠️ **GitHub.com Fallback** ⚠️