LINUX.ORG.RU

Богам юнит теста!

 , ,


1

3

Доброго времени суток, ЛОР!

Помогите нубу разобраться с модульным тестирование вообще и для Lua в частности. У меня нет понимания - на что в принципе можно протестировать некоторые вещи? Например, на что можно протестировать следующию функцию:

function slice(tbl, a, b, step)
    local ret, cnt = {}, 1
    if not b then
        a, b = 1, a
    end
    step = step or 1
	for i=a, b, step do
	    ret[cnt] = tbl[i]
	    cnt = cnt + 1
	end
    return ret
end

У меня фантазии хватило только на это:

function testSlice()
    local t = { 1, 2, 3 }
    assertNotNil( slice(t, 1, 2, 1) )
    assert( is_table( slice(t, 1, 2, 1) ) )
    assertNotNil( slice(t, 1, nil, 1) )
    assert( is_table( slice(t, 1, nil, 1) ) )
end

Тест покрывает эту функцию на 100%, но у меня остается сильное ощущение, что я не все учитываю. Поэтому прошу многоуважаемое сообщество подсказать мне, неопытному падавану, на что еще можно протестировать вышепиведенную функцию.

Заранее спасибо.

☆

Последнее исправление: Sektor (всего исправлений: 1)

юнит тесты разные бывают и пишутся в зависимости от своего предназначения в разное время и для разных задач.

к примеру, регрессионные пишутся чтобы баги не повторялись.

ты сначала подумай чего ты хочешь добиться, а то получается «мне надо скрепить 2 вот эти детали, но я не знаю как, какой стороной и зачем вообще».

BaBL ★★★★★
()
Ответ на: комментарий от BaBL

Ну вот данную функцию на что _вообще_ можно протестировать?

Sektor ☆
() автор топика

Тестировать нужно на то, что в будущем очень вероятно сломать. Что конкретно ты собираешься менять в этой функции, что может изменить ее функциональность?

vurdalak ★★★★★
()

Так как боги не торопятся появляться, выскажу свое скромное мнение. Каким образом можно разбить твою функцию? Некорректными параметрами. Вызови ее для списка нулевой длины.

PatrickKilpatrick ★
()
Ответ на: комментарий от PatrickKilpatrick

Каким образом можно разбить твою функцию? Некорректными параметрами. Вызови ее для списка нулевой длины.

А еще ее можно разбить при «a» и «step» = nil. Но это уже должны быть проверким внутри самой функции. А мне бы хотелось знать, что «внешне» у этой функции можно протестировать. Неужели только тип и «не nil» возвращаеиого значения?

Sektor ☆
() автор топика
Ответ на: комментарий от Sektor

Но это уже должны быть проверким внутри самой функции. А мне бы хотелось знать, что «внешне» у этой функции можно протестировать.

Нет. Насколько я понимаю это должны гарантировать внешние тесты. Грубо говоря внешние тесты должны гарантировать наличие внутренних.

PatrickKilpatrick ★
()

Простые функции на последовательнастях стоит тестить подобно методу мат индукции. Проверь, что функция работает на пустой таблице, на не пустой. Это так называемый happy-path. Потом проверь краевые случаи для входных параметров: для

b - a < 0,
b - a == 0,
b - a == len(tbl),
b - a > len(tbl),
 
step < 0,
step = 0,
step == len(tbl),
step > len(tbl),
step < b - a,
step == b - a,
step > b - a
dizza ★★★★★
()
Ответ на: комментарий от PatrickKilpatrick

Грубо говоря внешние тесты должны гарантировать наличие внутренних.

Согласен. Ну а пока у _конкретной_ функции какие проверки могут быть?

Sektor ☆
() автор топика

И да, толку от твоей проверки - assertNotNil, is_table. Ты с expected reult-ом сравнивай.

dizza ★★★★★
()

Вот хороший пример из хорошей книги.

Если TDD, я обычно тестирую:

  • Крайние случаи, например: нулевые данные, некорректные данные, граничные значения (если есть).
  • Поведение в неочевидных случаях, в вашем примере поведение, когда аргументы a, b, step, не заданы.
  • Типичные сценарии, от простых к сложным.
  • Смотрю, что может поменяться в коде например при отпимизации или рефакторинге, что можно при этом поломать, и если соотв. теста еще нет, добавляю его заранее.
  • Если есть смысл, стресс-тесты, проверка выхода за границы буфера, etc.

Богам юнит теста!

Зря такой заголовок :)

gv ★
()

Старайся больше внимания уделять крайним случаям и ошибкам. Вот пример на Ruby:

slice.rb:

def slice(arr, from, to = nil, step = nil)
  from, to = 0, from unless to
  step ||= 1

  raise TypeError unless arr.is_a? Array
  raise TypeError, 'Step and bounds must be integral' unless
    (step.is_a? Integer or step.is_a? Bignum) and
    (from.is_a? Integer or from.is_a? Bignum) and
    (to.is_a? Integer or to.is_a? Bignum)

  raise ArgumentError, 'Invalid slice bounds' if from > to
  raise ArgumentError, 'Array must be non-emtpy' if arr.empty?

  (from..to).step(step).each_with_object([]) do |idx, ret|
    ret << arr.fetch(idx)
  end
end

slice_spec.rb:

require_relative './slice.rb'

describe '#slice' do
  it 'should raise ArgumentError for empty array' do
    expect { slice [], 42 }.to raise_error(ArgumentError)
  end

  context 'with non-empty array' do
    subject(:arr) { [42, 15, 100500, 19, 24, 241, 412] }

    it 'should raise TypeError if argument types are invalid' do
      expect { slice arr, 0, 6, 2.5 }.to raise_error(TypeError)
      expect { slice arr, 0.5, 3 }.to raise_error(TypeError)
      expect { slice arr, 'to' }.to raise_error(TypeError)
      expect { slice true, 2 }.to raise_error(TypeError)
    end

    it 'should raise errors if slice bounds are invalid' do
      expect { slice arr, 5, 1 }.to raise_error(ArgumentError)
      expect { slice arr, 99 }.to raise_error(IndexError)
    end

    it 'should raise ArgumentError if step is negative' do
      expect { slice arr, 0, 1, -1 }.to raise_error(ArgumentError)
    end

    it 'should slice the whole array' do
      expect(slice(arr, arr.length - 1).length).to eq(arr.length)
      expect(slice arr, arr.length - 1).to eq(arr)
    end

    it 'should slice with given range' do
      expect(slice arr, 1, 5).to eq([15, 100500, 19, 24, 241])
    end

    it 'should slice with given range and step' do
      expect(slice arr, 1, 5, 2).to eq([15, 19, 241])
    end
  end

  # and so on...
end

Естественно, какую ситуацию считать ошибочной, — решать тебе.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

slice_spec.rb

Классная штука этот rspec, спасибо за пример.

gv ★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.