Макетные зависимости тестируемого класса - PullRequest
0 голосов
/ 24 сентября 2018

Я хочу протестировать некоторый код, который написан для запуска на встроенном процессоре в проекте Visual Studio Native Unit Test.

В классе TestMe есть несколько методов, которые являются хорошими кандидатами для тестирования, но классы Foo и Bar напрямую обращаются к отображенным в памяти регистрам, которые доступны только на встроенном процессоре.

#pragma once

#include "Foo.h"
#include "Bar.h"

class TestMe
{
public:
    TestMe(Foo& aFoo, Bar& aBar);
    ~TestMe();

    float FooBar();

};

Что такоелучший способ макетировать эти объекты, чтобы я мог проверить класс TestMe?

Редактировать: Для меня лучшим способом был бы тот, который как можно меньше мешает тестируемому программному обеспечению.

Ответы [ 4 ]

0 голосов
/ 02 октября 2018

В зависимости от размера и ограничений производительности встроенной платформы введение интерфейсов с единственной целью модульного тестирования может быть плохой идеей.Для небольших систем я предпочитаю подход классов с псевдонимами типов, которые представляют некоторую периферию процессора.Я полагаю, это также то, что представляют "Foo" и "Bar" в вашем примере.

Правильный псевдоним типа для текущей цели можно выбрать с помощью предопределений архитектуры

struct Uart1 {};
struct Uart1Mock {};

#ifdef __x86_64__
    using SensorUart = Uart1Mock;
#else
    using SensorUart = Uart1;
#endif

Код приложениязатем просто использует SensorUart, независимо от того, зависит ли класс от фактического последовательного порта или просто использует стандартный io.

0 голосов
/ 24 сентября 2018

Ваши Foo и Bar передаются конструктору по ссылке.Есть два подхода к этому.

Моя личная польза - использовать интерфейс и использовать полиморфные объекты.

Так это выглядит так:

class IFoo {
public:
     virtual void someFunction() = 0;
};

class IBar {
public:
     virtual void otherFunction() = 0;
};

class Foo : public IFoo {
    ....
    void someFunction() {
    }
};

class Bar : public IBar {
     .....
     void otherFunction() {
     }  
};

class TestMe {
public:
    TestMe(IFoo& aFoo, IBar& aBar);
    ~TestMe();

    float FooBar();
};

// test code (GMock example):
class MockFoo : public IFoo {
    MOCK_METHOD(someFunction(), void());
};

class MockBar : public IBar {
     MOCK_METHOD(otherFunction(), void());
};

TEST(TestMeTest, someTest)
{
   MockBar bar;
   MockFoo foo; 
   TestMe testMe(bar, foo);

   EXPECT_CALL(bar, otherFunction());

   EXPECT_EQ(0.2, testMe.FooBar());
}

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

Оба подхода имеют свои плюсы и минусы, и вы сами выбираете, какой из них лучше в вашем случае.

0 голосов
/ 24 сентября 2018

Существует решение не вводить интерфейсы только для целей тестирования (: Подстановка времени ссылки.

Правила:

  • Foo и Bar находятся в статической библиотеке (может бытьотдельные библиотеки для Foo и Bar)
  • Не связывайте эти библиотеки с test exec.
  • Создайте фиктивную реализацию, которая будет связана с test exec:

Файл Hpp:

#pragma once
#include <gmock/gmock.h>

class FooMock
{
    FooMock();
    ~FooMock();

    MOCK_METHOD0(foo, void());
};

Файл Cpp:

#include "Foo.hpp"
#include "FooMock.hpp"

namespace
{
    FooMock* fooMock;
}

FooMock::FooMock()
{
    assert(!fooMock);
    fooMock = this;
}

FooMock::~FooMock()
{
    fooMock = nullptr;
}

// Implement real Foo::foo
void Foo::foo()
{
    // call FooMock::foo
    fooMock->foo();
}

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

0 голосов
/ 24 сентября 2018

«Наилучшее» всегда субъективно, но мне нравится использовать шаблоны для такого рода насмешек:

template <typename TFoo, typename TBar>
class TestMeImpl
{
public:
    TestMeImpl(TFoo& aFoo, TBar& aBar);
    ~TestMeImpl();

    float FooBar();
};

using TestMe = TestMeImpl<Foo, Bar>;

Вы бы написали юнит-тесты против TestMeImpl, но выставили бы TestMe для своих пользователей.

...