C#: Как протестировать основной потоковый класс рабочего

Собственный C++ intellisense не работает надежно ни в какой версии Visual Studio. Я нахожу, что существует две типичных проблемы:

1) пути Заголовочного файла не являются установкой правильно. При нахождении типа, где intellisense не работает, используйте IDE для нажатия через каждый заголовочный файл для нахождения того, содержащего тип. (Щелкните правой кнопкой по #include, и выбор Открывать Document...). Если это перестало работать, прежде чем Вы доберетесь до файла, который объявляет тип тогда, это - Ваша проблема. Удостоверьтесь, что пути поиска заголовочного файла являются установкой правильно.

И,

2) intellisense база данных повреждена. Это происходит Все время. Необходимо закрыть решение, удалить .ncb файл, и затем вновь открыть решение. Я отправил макрос, который я использую для этого в ответе на другой вопрос здесь .

препроцессор может также перепутать intellisense - поэтому удостоверьтесь, что любые #defines во время сборки также доступны intellisense. Кроме этого, я не знаю то, что еще может повредить его. Я не видел никаких конкретных проблем с предописаниями.

5
задан Svish 20 November 2009 в 14:37
поделиться

4 ответа

Вам необходимо использовать ManualResetEvent - подробнее см. Модульное тестирование многопоточных асинхронных событий .

Что-то вроде:

[Test]
public void DoWork_WhenDone_EventIsRaised()
{
   var worker = new Worker();

   var eventWasRaised = false;
   var mre = new ManualResetEvent(false);
   worker.Done += (s, e) => { eventWasRaised= true; mre.Set(); };

   worker.Work();
   mre.WaitOne(1000);
   Assert.That(eventWasRaised);
}
7
ответ дан 13 December 2019 в 22:10
поделиться

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

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

1
ответ дан 13 December 2019 в 22:10
поделиться

Вы можете использовать общий шаблон, который раскрывает создание потока внешнему классу.

В классе извлекает создание потока в виртуальный метод:

class Worker
{
    public event EventHandler<EventArgs> Done = (s, e) => { };

    public void StartWork()
    {
        var thread = CreateThread();
        thread.Start();
    }

    // Seam for extension and testability
    virtual protected Thread CreateThread()
    {
        return new Thread(Work) { Name = "Worker Thread" };
    }

    private void Work()
    {
        // Do some heavy lifting
        Thread.Sleep(500);
        Done(this, EventArgs.Empty);
    }
}

Определите подкласс, который предоставляет поток :

class WorkerForTest : Worker
{
    internal Thread thread;

    protected override Thread CreateThread()
    {
        thread = base.CreateThread();
        return thread;
    }
}

Синхронизация теста с потоком:

[TestFixture]
class WorkerTests
{
    [Test]
    public void DoWork_WhenDone_EventIsRaised()
    {
        var worker = new WorkerForTest();

        var eventWasRaised = false;
        worker.Done += (s, e) => eventWasRaised = true;

        worker.StartWork();

        // Use the seam for synchronizing the thread in the test
        worker.thread.Join();
        Assert.That(eventWasRaised);
    }
}

Этот вариант дизайна для тестируемости имеет преимущества перед синхронизацией тестового потока, переводя его в спящий режим перед утверждением:

  • Он не будет иметь ложноотрицательных отказов, как это могло бы быть, когда перевод тестового потока в спящий режим на период, которого обычно достаточно для завершения рабочего потока.
  • Он не будет работать медленнее, чем должен, потому что время сна требует буфера для уверенности. Это важно, когда от него зависят многие тесты в наборе.
1
ответ дан 13 December 2019 в 22:10
поделиться

Здесь может быть два варианта: 1) Добавьте к работнику метод ожидания, чтобы вы могли дождаться завершения 2) Вместо простого логического объекта использовать событие (AutoResetEvent)

Как правило, каждое ожидание должно ждать указанного тайм-аута. В приведенных ниже примерах ожидание бесконечно.

Первый вариант:

class Worker
{
 //...
    Thread thread;

    public void StartWork()
    {
        thread = new Thread(Work) { Name = "Worker Thread" };
        thread.Start();
    }

   void WaitCompletion()
   {
     if ( thread != null ) thread.Join(); 
   }
 //...
}

[TestFixture]
class WorkerTests
{
    [Test]
    public void DoWork_WhenDone_EventIsRaised()
    {
        var worker = new Worker();

        var eventWasRaised = false;
        worker.Done += (s, e) => eventWasRaised = true;

        worker.Work();
        worker.WaitCompletion();

        Assert.That(eventWasRaised);
    }
}

Второй вариант: (Ожидание может быть выполнено с тайм-аутом)

[TestFixture]
class WorkerTests
{
    [Test]
    public void DoWork_WhenDone_EventIsRaised()
    {
        var worker = new Worker();

        AutoResetEvent eventWasRaised = new AutoResetEvent(false);
        worker.Done += (s, e) => eventWasRaised.Set();

        worker.Work();
        Assert.That(eventWasRaised.WaitOne());
    }
}
1
ответ дан 13 December 2019 в 22:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: