пятница, 6 сентября 2013 г.

jMockit. State-based testing and Fakes

Один из двух подходов jMockit
Построено на реализации:
State-based testing не фокусируется на взаимодействии между тестируемым классом/юнитом и его зависимостями, а -- на саммих данных которыми обмениваются обьекты. Тесты пишутся не из перспективы теструемого класса, а с перспективы используемых классов, и не важно юнит это или депенденси. Главное в этим виде тесрирования сделать сверку в конце тестового метода, чтобы наши предположения совпали.

Понятия фейков характерны для интеграционного тестирования, где мы вяжемся на какието внешние сервисы, где мы их имитируем и не зависим от их текущего состояния.



1) Мокирование конструктора класса.
  ...
  @Test
  public myTestMethod(){
    new MockUp<MyClass>(){
      @Mock void $init(){...}
    }

    MyClass ob = new MyClass();//calling mocked-constructor
  }

2) Мокирование из интерфейса класса, готовый к использованию в тесте
  ...
  @Test
  public myTestMethod(){
    MyInterface instOfPseudoReal = new MockUp<MyInterface>(){
      @Mock void SomeMethod(){...}
      ...
    }.getMockInstance();//return null if MyInterface is Class
  }

3) Мокирование методов класса, статических методов класса, финальных классов.
Все это позволяется делать по одной схеме - определении соотвествующего метода в одном стиле как для статического так и нет, при этом не важно какой уровень доступа мы ставим реализации и совпадает ли он с мокируемым методом - для экономии места лучше всегда писать пакетный уровень
@Test
  public myTestMethod(){
    new MockUp<MyClass>(){
      @Mock void staticMethod(){...}

      @Mock void method(){...}
    }

    MyClass ob = new MyClass();
    ob.method();//calling mock of method
    MyClass.staticMethod();//calling static method
  }

4) Определение к-ва обращений к методам
  @Test
  public myTestMethod(){
    new MockUp<MyClass>(){
      @Mock(minInvocations = 1)
      void method1(){...}

      @Mock(invocations = 1)
      void method2(){...}

      @Mock(maxInvocations = 1)
      void method3(){...}

      @Mock(minInvocations = 1, maxInvocatioins = 5)
      void method4(){...}
    }

    MyClass ob = new MyClass();
    ob.method();//calling mock of method
    MyClass.staticMethod();//calling static method
  }

4. Мокирование class initializers(Static initialization blocks, static fields, initialization non-static blocks)
  ...
  new MockUp<MyClass>(){
    @Mock void $clinit(){...}
  }

5. Контекс вызова.
Если поставить в определение любого метода первым параметр Invocation inv, то при вызове мокированого метода, мы получаем ссылку на this(инстанция обьекта), параметры и другое; в случае static-метода -- null.
  ...
  new MockUp(){
    @Mock $init(Invocation inv, String name, Subject sub){
      assertEquals(1, invocation.getInvocationCount());

      LoginContext _this = inv.getInvokedInstance();
      Deencapsulation.setField(_this, "name", name);
      Deencapsulation.setField(_this, "subject", sub);
    }
  };

  LoginContext theMockedInstance = new LoginContext("test", someSubjectObj);
  ..

6. Reentrant mocks.
Можна делать мок на метод, внутри который все-таки делает обращение в оригинальный метод. Это похоже на advice из AOP.
  @Mock void logout(Invocation inv){
    try{
      inv.proceed();
    }finally{...}
  }


7. Reusing mocks between tests.
Есть два варианта:
  1. Создавать их в методах помеченных @Before/@BeforeMethod(TestNG).
  2. Создавать неанонимные классасы расширяя MockUp и потом создавать инстанции в конкретных нужных тестовых методах, по необходимости в определенном тесте мы можем создать анонимную интсанцию равширив их и перегрузить нужные методы на месте.

Комментариев нет:

Отправить комментарий