Тестирование софта - статьи

       

Генерируемый SeC-код


В первую очередь необходимо чётко определить, как должен выглядеть генерируемый код, что именно и как именно он будет проверять. За основу, разумеется, были взяты созданные к этому времени наработки, написанные вручную. Весь однотипный код удобно заменить набором макросов (они поддерживаются в языке SeC, т. к. он включает в себя все возможности языка C). Это сделало бы исходный текст более наглядным и более простым для написания и отладки.

В стандарте LSB присутствуют несколько разных типов требований на поведение функций при возникновении ошибочной ситуации. Возможные варианты поведения функции в случае ошибки могут быть описаны следующим образом:

  • SHALL: в стандарте присутствует фраза «The function shall fail if …», т. е. стандарт требует, чтобы функция всегда обнаруживала описанную ошибочную ситуацию и возвращала в этом случае определённый код ошибки.
  • MAY: в стандарте присутствует фраза «The function may fail if …», т. е. стандарт не требует непременного обнаружения данной ошибочной ситуации, но в случае, если функция всё же реагирует на данную ошибку, её поведение должно быть таким, как описано в стандарте.
  • NEVER: в стандарте присутствует фраза «The function shall not return an error code …», т. е. данный код ошибки не может быть возвращён ни при каких условиях.

Эти три типа требований и были взяты за основу.

Проверка кодов ошибок должна производиться до начала проверки остальных требований (за исключением, быть может, самых базовых аспектов, обеспечивающих непосредственное функционирование самой тестовой системы - таких как проверки на NULL). Это связано с тем, что если произошла ошибка, то функция не выполнила требуемое от неё действие, и, следовательно, проверки функциональных требований сообщат, что функция работает некорректно, т. е. не удовлетворяет стандарту. Однако ошибка могла быть вызвана тестовым сценарием намеренно (например, специально для того, чтобы проверить, как поведёт себя функция в этом случае), и тогда сообщение о некорректности поведения функции окажется ложной тревогой.
Именно поэтому в первую очередь должен отработать блок проверки ошибочных ситуаций, и только если ошибка не была возвращена (и не ожидалась!), управление передаётся дальше, на код проверки основных требований. Для удобства проверка кодов ошибок оформлена в виде блока, ограниченного операторными скобками ERROR_BEGIN и ERROR_END, которые являются макросами. ERROR_BEGIN при этом содержит параметры, глобальные для всего блока (например, в какой переменной хранится собственно код ошибки). Внутри блока располагаются индивидуальные проверки для каждого пункта, упомянутого в стандарте, которые также являются вызовами макросов с определённым набором параметров. Упомянутым выше трём основным типам требований соответствуют макросы ERROR_SHALL, ERROR_MAY и ERROR_NEVER. Помимо них, есть ещё некоторые дополнительные макросы, но о них мы расскажем ниже. Приведём небольшой пример, демонстрирующий, как выглядит блок проверки кодов ошибок в одной из подсистем: Текст стандарта: The pthread_setspecific() function shall fail if: [ENOMEM] Insufficient memory exists to associate the non-NULL value with the key. The pthread_setspecific() function may fail if: [EINVAL] The key value is invalid. These functions shall not return an error code of [EINTR]. Текст спецификации: ERROR_BEGIN(POSIX_PTHREAD_SETSPECIFIC, "pthread_setspecific.04.02", pthread_setspecific_spec != 0, pthread_setspecific_spec) /* * The pthread_setspecific() function shall fail if: * [ENOMEM] * Insufficient memory exists to associate the non-NULL value with * the key. */ ERROR_SHALL(POSIX_PTHREAD_SETSPECIFIC, ENOMEM, "!pthread_setspecific.05.01", /* условие */) /* * The pthread_setspecific() function may fail if: * [EINVAL] * The key value is invalid. */ ERROR_MAY(POSIX_PTHREAD_SETSPECIFIC, EINVAL, "pthread_setspecific.06.01", !containsKey_Map(thread->key_specific, key)) /* * These functions shall not return an error code of [EINTR]. */ ERROR_NEVER(POSIX_PTHREAD_SETSPECIFIC, EINTR, "pthread_setspecific.07") ERROR_END() Параметры макросов имеют следующий смысл: ERROR_BEGIN(ERR_FUNC, REQID, HAS_ERROR, ERROR_VAL):

  • ERR_FUNC - идентификатор функции, используемый в качестве префикса для конфигурационных констант.


    Например, с префикса POSIX_PTHREAD_SETSPECIFIC начинаются соответствующие конфигурационные константы, такие как:
    • POSIX_PTHREAD_SETSPECIFIC_HAS_EXTRA_ERROR_CODES
    • POSIX_PTHREAD_SETSPECIFIC_FAILS_WITH_EINVAL и др.
  • REQID - идентификатор проверяемого требования (строковая константа).
  • HAS_ERROR - предикат, определяющий условие возникновения ошибки (булевское выражение).
  • ERROR_VAL - код ошибки (обычно это переменная errno или возвращаемое значение функции).
ERROR_MAY(ERR_FUNC, ERRNAME, REQID, ERROR_PREDICATE), ERROR_SHALL(ERR_FUNC, ERRNAME, REQID, ERROR_PREDICATE), ERROR_NEVER(ERR_FUNC, ERRNAME, REQID):
  • ERR_FUNC - то же, что и выше.
  • ERRNAME - имя константы, соответствующей ожидаемому коду ошибки. Например, ENOMEM, EINVAL.
  • REQID - идентификатор проверяемого требования.
  • ERROR_PREDICATE - предикат, определяющий условие возникновения ошибки.
ERROR_END: параметров не требует.

Содержание раздела