2015-11-02 3 views
14

Проблема:ожидать() без реальных ожиданий

В последнее время во время просмотра наших существующих тест-кодовую, я заметил опасный вид опечатка/ошибка, когда expect() использовали без «согласования» части:

expect(page.filters.fromDateLabel.getText(), "After"); 

Я уверен, что toEqual() должен был быть использован здесь:

expect(page.filters.fromDateLabel.getText()).toEqual("After"); 

Th Проблема в том, что jasmine не преминул бы ожидать в этом случае (ну, очевидно, потому что ничего не ожидалось). И это ставит нас к более серьезной проблеме - ничто не было фактически проверено в тестовом примере - это проходило без каких-либо ожиданий. Мы получили ложное представление о том, что было проверено.

Вопрос:

Я хочу, чтобы поймать эти ошибки как можно быстрее. Как вы думаете, как я должен справиться с этой проблемой?

Мысль:

  • как-то провалить тест, если не было никаких ожиданий, сделанные в нем (не уверены, что если jasmine имеет ничего подобного встроенный)
  • «пятачка» вопрос expect() и предупреждение/вызвать ошибку, если ничего не называли на «ожидать» часть
  • анализа использования статического кода - определить пользовательское eslint правило
+2

Верховенство пуха бы мое предпочтение, как это наименее инвазивный – Phil

+0

@Phil Я согласен, это то, что я собираюсь попробовать первым, так как это звучит как самый простой вариант - + у нас уже есть набор настраиваемых правил eslint. Вообще говоря, мне также нравится вариант №1 - вероятно, имеет смысл указать разработчику e2e, что он/она фактически ничего не проверял в тесте. – alecxe

+0

@Phil и да, в идеальном мире такие вещи не должны происходить, так как разработчик, пишущий тест, должен увидеть неудачу теста и убедиться, что он проверяет, что должно было быть проверено. Но опечатки и ошибки случаются со всеми - я просто хочу, чтобы эти вещи оказались «свежими» :) – alecxe

ответ

7

Пользовательское правило ESLint, предоставленное в ответе, теперь является частью eslint-plugin-jasmine 1.6.0:


Старый Ответ:

Вот custom ESLint rule я закончил с:

module.exports = function (context) { 
    return { 
    // checking "expect()" arguments 
    CallExpression: function (node) { 
     if (node.callee.name === 'expect') { 
     if (node.arguments.length > 1) { 
      context.report(node, 'More than one argument passed to expect()') 
     } else if (node.arguments.length === 0) { 
      context.report(node, 'No arguments passed to expect()') 
     } 
     } 
    }, 

    // nothing called on "expect()" 
    'CallExpression:exit': function (node) { 
     if (node.callee.name === 'expect' && node.parent.type === 'ExpressionStatement') { 
     context.report(node, 'Nothing called on expect()') 
     } 
    } 
    } 
} 

Он проверяет на 3 вещи:

  • более 1 аргумент, переданный expect()
  • аргументы не передаются expect()
  • не было ничего призвал expect()

Вот образец недействителен expect() обыкновений в настоящее время он улавливает:

expect(page.filters.fromDateLabel.getText(), "After"); 
expect("After"); 
expect(); 

Что касается опции # 1, на самом деле весьма родственный и полезным ESLint правило быть уже реализованы и с открытым кодом с помощью [eslint-plugin-jasmine]:

1

Я склонен думать, что маршрут статического анализа лучше всего, но если вы ищете быстрый и грязный способ, вот какой код, который захватывает ожидания, возвращаемые всеми вызовами expect, и создает прокси-сервер, который отслеживает, будет ли какой-либо из свойства ожидания были когда-либо использовали:

var unusedExpectations = new Set(); 

var originalExpect = window.expect; // Should be empty after every spec 
var expect = function() { 
    var rawExpectation = originalExpect.apply(this, arguments); 
    unusedExpectations.add(rawExpectation); // Assume unused until used 

    // Traverse expectation and its prototypes, copying all properties to 
    // our proxy object. (Note that this becomes much simpler if you have 
    // ES6 Proxy in your environment.) 

    var proxy = {} 
    for(var proto = rawExpectation; proto; proto = proto.__proto__) { 
    Object.getOwnPropertyNames(proto).forEach(function(prop) { 
     if(Object.getOwnPropertyDescriptor(proxy, prop)) 
     return; 
     Object.defineProperty(
     proxy, prop, { 
      get: function() { 
      // Aha! Somebody used this expectation for _something_. 
      unusedExpectations.delete(rawExpectation); 
      return rawExpectation[prop]; 
      } 
     } 
    ); 
    }); 
    } 
    return proxy; 
} 

Put, что в месте, где он прячется Жасмин expect из ваших спецификаций, а затем:

beforeEach(function() { 
    unusedExpectations.clear(); 
}); 
afterEach(function() { 
    expect(unusedExpectations.size).toEqual(0); 
}); 

предостережения:

  1. Вид зла.
  2. Не поймать expect(foo).toBeFalsy; (отсутствует парсеры).
  3. Подсчитывает использование любого имущества, поэтому не поймает expect(foo).toString().

Все еще, это работает!

Можно было бы добавить код, чтобы проверить трассировку стека и извлечь местоположение оскорбительного expect(), но я думаю, что флагов, который имеет неиспользованный expect(), является достаточным.

+0

Это интересная злая идея! :) Я обязательно попробую это на практике! Я также разместил решения для вариантов №1 и №3 - я думаю, у нас есть полная картина здесь со всеми различными подходами. Благодаря! – alecxe

Смежные вопросы