Я пишу модульные тесты и пытаюсь покрыть весь мой код.

У меня есть в моем коде что-то вроде этого:

template<typename ValueType>
std::string ConvertToStringUsingBoost(ValueType const& v)
{
    try 
    {
        return boost::lexical_cast<std::string, ValueType>(v);
    }
    catch(boost::bad_lexical_cast const& e)
    {
        LOG_ERR("Fail to cast %s to string", e.source_type().name);
        return std::string();
    }
}

Я читал эти документы и не смог найти ни одного информация о том, когда boost::lexical_cast - std::string может вызвать исключение.

Можете ли вы помочь мне с этим?

Если это невозможно, я просто удалю эту попытку. Если это возможно, я бы предпочел рассмотреть это в модульном тестировании.

9
Grigorii Alekseev 1 Май 2019 в 14:30

3 ответа

Лучший ответ

Например, может произойти сбой, если выбрано пользовательское преобразование:

enum class MyType {};

std::ostream& operator<<( std::ostream&, MyType const& )
{
    throw "error";
}

int main()
{
    try 
    {
        boost::lexical_cast< std::string >( MyType{} );
    }
    catch(...)
    {
        std::cout << "lexical_cast exception";
    }
}

Поскольку у вас нет контроля над типом исключений, генерируемых пользовательскими преобразованиями, перехват boost::bad_lexical_cast будет недостаточным. Ваш юнит тест должен отловить все исключения.

Live Demo

7
zett42 1 Май 2019 в 12:23

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

template<typename ValueType>
std::string ConvertToStringUsingBoost(ValueType const& v)
{
    try 
    {

#ifdef UNITTEST
      if (unittest == case_fail) {
        throw boost::bad_lexical_cast();
      }
#endif
        return boost::lexical_cast<std::string, ValueType>(v);
    }
    catch(boost::bad_lexical_cast const& e)
    {
        LOG_ERR("Fail to cast %s to string", e.source_type().name);
        return std::string();
    }
}

Теперь вы должны быть в состоянии охватить это ~ 100% кода!

1
Lightness Races in Orbit 2 Май 2019 в 09:30

Я не могу придумать причину, по которой лексическое приведение к строке должно вызывать bad_lexical_cast, за исключением пользовательских типов. Если оператор вставки потока ValueType может установить флаг ошибки в потоке, то это приведет к bad_lexical_cast. В противном случае нет.

Лично я бы оставил catch внутри, даже если вы просто конвертируете встроенные модули, такие как int s; это не повредит, и может поймать ошибки, если вы каким-либо образом измените lexical_cast, или если есть какой-то крайний случай, который ни вы, ни я не рассмотрели; если вы не обработаете полученное исключение, вы получите прерывание во время выполнения!

Если вы беспокоитесь об издержках исключения, вы можете использовать try_lexical_cast и убедитесь, что он возвращает true, а не перехватывает. Однако, если оператор вставки потока ValueType может выдать, вам все равно потребуется возможность перехватить это исключение.

10
Lightness Races in Orbit 1 Май 2019 в 12:57