package com.lzf.learn.testing.junit.parameter;

import com.lzf.learn.testing.junit.parameter.test.Person;
import com.lzf.learn.testing.junit.parameter.test.PersonProvider;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;


/**
 * TestJUnitParams参数化的测试_推荐
 *
 * @author Jamefeng liu
 * @date 2016-12-25
 */
@RunWith(JUnitParamsRunner.class)
public class TestJUnitParams参数化的测试_推荐 {
    /**
     * 测试可以动态地注入数据
     *
     *   推荐使用： JUnitParams （需要maven引入）
     *
     *   1. 下面是使用 Parameterized Runner实现了参数测试 (可以格式化 junit的显示)
            ① 构造函数 入参
            ② 注解方式 入参， 只能空构造函数
            顺序：
                 1. 首先会初始化@Parameters注解标记的数据.
                 2. 然后循环这些数据
                 3. 每一个循环中的值都会传递（注入）到构造函数FibonacciTest(int input, int expected)中
                 4. test()中的断言
     *   2. JUnitParams 参考另外一个类
            跟JUnit标准的Parametrised runner的主要区别：
                 ① 更明确 - 参数不再是类的属性,而是方法级别的参数
                 ② 更少的代码量 - 你不再需要写一个构造方法来设置参数
                 ③ 也可以在Parametrised类中的非Parametrised方法混合使用
                 ④ 数可以通过CSV字符串或者parameters供应类来传递
                 ⑤ parameters供应类提供了足够多的参数让你能够区分不同的测试场景
                 ⑥ 你可以写一个测试方法来提供参数(没有外部类或者静态属性的话)
                 ⑦ 你可以在你的IDE中看到明确的参数(在JUnit的Parametrised中只可以看到参数的序号)

            步骤：
                 ①类上  @RunWith(JUnitParamsRunner.class)
                 ②可以使用下面四种方式入参
                    1. 方法上注解_入参
                    2. 方法上注解_指定入参的方法
                    3. 约定的方式入参(就是约定俗称的方法： 以parametersFor开头+测试方法名 )
                    4. 通过依赖外部类

     */

    @Test
    @Parameters({ "17, false", "22, true" })
    public void test入参方式1_方法上注解_入参_判断是否是成年人(int age, boolean valid) throws Exception {
        assertThat(new Person(age).isAdult(), is(valid));
    }


    @Test
    @Parameters(method = "test入参方式2_方法上注解_指定入参的内容")  //
    public void test入参方式2_方法上注解_指定入参的方法_判断是否是成年人(int age, boolean valid) throws Exception {
        assertEquals(valid, new Person(age).isAdult());
    }
    private Object[] test入参方式2_方法上注解_指定入参的内容() {
        return new Object[]{
                new Object[]{13, false},
                new Object[]{17, false},
                new Object[]{18, true},
                new Object[]{22, true}
        };
    }


    /**
     *
     * 将提供值的方法的名称跟你的测试方法名类似（以parametersFor开头+测试方法名）  (测试方法名第一个要大写)
     *
     */
    @Test
    @Parameters
    public void test入参方式3_约定的方式入参_判断是否是成年人(int age, boolean valid) throws Exception {
        assertEquals(valid, new Person(age).isAdult());
    }
    //在方法里testxx似乎必须大写的开头TestXXX
    private Object[] parametersForTest入参方式3_约定的方式入参_判断是否是成年人() {
        return new Object[]{
                new Object[]{13, false},
                new Object[]{17, false},
                new Object[]{18, true},
                new Object[]{22, true}
        };
    }


    @Test
    @Parameters
    public void test入参方式3_约定的方式入参2_使用对象_判断是否是成年人(Person person, boolean valid) throws Exception {
        assertThat(person.isAdult(), is(valid));
    }
    //在方法里testxx似乎必须大写的开头TestXXX
    private Object[] parametersForTest入参方式3_约定的方式入参2_使用对象_判断是否是成年人() {
        return new Object[]{
                new Object[]{new Person(13), false},
                new Object[]{new Person(17), false},
                new Object[]{new Person(18), true},
                new Object[]{new Person(22), true}
        };
    }

    @Test
    @Parameters(source = PersonProvider.class)
    public void test入参方式4_通过依赖外部类_判断是否是成年人(Person person, boolean valid) {
        assertThat(person.isAdult(), is(valid));
    }
}
