Результат NUnit отличается в отладке и выпуске

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

Я пытаюсь обнаружить ошибки привязки. Вот образец

[TestFixture, RequiresSTA]
public class BindingTests
{
    [Test]
    public void T1_BindingErrorsExpected()
    {
        string error = null;
        using (var listener = new ObservableTraceListener())
        {
            listener.TraceCatched += s => error = s;

            TextBlock myText = new TextBlock();
            UserControl control = new UserControl();
            Binding myBinding = new Binding("BadBinding");
            myBinding.Source = control;
            myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
        }
        Assert.IsNotNull(error);
    }
}

И ObservableTraceListener

public sealed class ObservableTraceListener : DefaultTraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();
    public ObservableTraceListener()
    {
        PresentationTraceListener.Add(SourceLevels.Error, this);
    }

    public new void Dispose()
    {
        Flush();
        Close();
        PresentationTraceListener.Remove(this);
        base.Dispose();
    }   

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        Write(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}


public static class PresentationTraceListener
{
    public static void Add(SourceLevels level, TraceListener trace)
    {
        PresentationTraceSources.DataBindingSource.Listeners.Add(trace);
        PresentationTraceSources.DataBindingSource.Switch.Level = level;
        PresentationTraceSources.ResourceDictionarySource.Listeners.Add(trace);
        PresentationTraceSources.ResourceDictionarySource.Switch.Level = level;
    }

    public static void Remove(TraceListener trace)
    {
        PresentationTraceSources.DataBindingSource.Listeners.Remove(trace);
        PresentationTraceSources.ResourceDictionarySource.Listeners.Remove(trace);
    }
}

Результат в отладке -> Ошибка (что я ожидаю)

Результат в Run-> Success (не то, что ожидалось)


person Heyjee    schedule 25.11.2014    source источник
comment
Я предполагаю, что это связано с побочными эффектами от DefaultTraceListener, который пытается вызвать старый механизм трассировки (OutputDebugString). Какова была мотивация использования этого класса в качестве базового вместо производного от TraceListener?   -  person MatthewMartin    schedule 26.11.2014
comment
Нет конкретной причины. Завтра я попробую внедрить traceListener и дам вам обратную связь.   -  person Heyjee    schedule 26.11.2014
comment
Я только что проверил с public sealed class ObservableTraceListener : TraceListener вместо public sealed class ObservableTraceListener : DefaultTraceListener, и это не решило проблему.   -  person Heyjee    schedule 26.11.2014
comment
я только что обновил свой пример, и когда я нахожусь в режиме отладки, вызов TraceListner вызывается функцией myText.SetBinding(). В режиме выполнения метод setBinding не вызывает исключения. Если это может помочь...   -  person Heyjee    schedule 26.11.2014


Ответы (2)


Спасибо, МэтьюМартин, но я нашел решение, глядя на https://github.com/bblanchon/WpfBindingErrors.

Проблемой был мой ObservableTraceListener.

Мне нужно было добавить статический конструктор, вызывающий PresentationTraceSources.Refresh(), чтобы он работал правильно. Как сказано в документе MSDN, это Refreshes trace sources, by forcing the app.config file to be re-read. Итак, некоторая инициализация была только что выполнена, когда я начал тест в режиме «отладки», что, вероятно, привело к чтению файла app.config.

Документ MSDN -> PresentationTraceSources.Refresh() http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.refresh%28v=vs.100%29.aspx

Вот мой последний ObservableTraceListener, а PresentationTraceListener такой же, как и в вопросе

public sealed class ObservableTraceListener : TraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();


    static ObservableTraceListener()
    {
        PresentationTraceSources.Refresh();
    }

    public ObservableTraceListener()
    {
        PresentationTraceListener.Add(SourceLevels.Error, this);
    }

    public new void Dispose()
    {
        Flush();
        Close();
        PresentationTraceListener.Remove(this);
        base.Dispose();
    }   

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        _Builder.Append(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}
person Heyjee    schedule 26.11.2014

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

В Интернете нет ссылки на PresentationTraceListener - то, как он обрабатывает TraceListener, важно, потому что AFAIK PresentationTraceListener - это то, что вызывает методы Write/WriteLine TraceListener (возможно, косвенно через TraceSource)

Этот код ниже компилируется в новый проект. Если я Write(x), я получаю null, если я записываюLine(x), я получаю значение. Как правило, когда вы пишете собственный TraceListener, вы перенаправляете все перегрузки в один метод, чтобы все они вели себя одинаково (Write и WriteLine должны быть идентичными, за исключением того, что WriteLine добавляет новую строку к сообщению для вызывающей стороны).

Еще одно наблюдение заключается в том, что трассировка System.Diagnostics — это причудливая библиотека ведения журналов, основное преимущество которой заключается в том, что она всегда доступна, даже если есть какой-то барьер для использования сторонних библиотек. Трассировка System.Diagnostics действительно хочет, чтобы вы зарегистрировали TraceSwitch, TraceListener в своем app.config или web.config и использовали их для включения и отключения трассировки. Это также требует регистрации флага TRACE (так же, как регистрируется флаг DEBUG, в свойствах проекта - по умолчанию TRACE определен для DEBUG и RELEASE)

[TestFixture, RequiresSTA]
public class BindingTests
{
    [Test]
    public void T1_BindingErrorsExpected()
    {
        string error = null;
        using (var listener = new ObservableTraceListener())
        {
            listener.TraceCatched += s => error = s;

            //TextBlock myText = new TextBlock();
            //UserControl control = new UserControl();
            //Binding myBinding = new Binding("BadBinding");
            //myBinding.Source = control;
            //myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
            PresentationTraceSources.DataBindingSource.TraceEvent(TraceEventType.Error,0, "Hello World!");    
        }
        Assert.IsNotNull(error);
        Console.WriteLine(error);

    }
}

public sealed class ObservableTraceListener : TraceListener
{
    private readonly StringBuilder _Builder = new StringBuilder();
    public ObservableTraceListener()
    {
        //PresentationTraceListener.Add(SourceLevels.Error, this);
    }
    protected override void Dispose(bool disposing)
    {
        Flush();
        Close();
        //PresentationTraceListener.Remove(this);
    }

    public override void Write(string message)
    {
        _Builder.Append(message);
    }

    public override void WriteLine(string message)
    {
        Write(message);

        if (TraceCatched != null)
            TraceCatched(_Builder.ToString());

        _Builder.Clear();
    }

    public event Action<string> TraceCatched;
}
person MatthewMartin    schedule 26.11.2014
comment
извините, PresentationTraceListener — это мой собственный класс. я редактирую свой пост - person Heyjee; 26.11.2014
comment
Хорошо, PresentationTraceSources.DataBindingSource — это обычный TraceSource, и при прямом вызове он работает нормально, как в DEBUG, так и в RELEASE на моей машине. Я заметил, что ошибка содержит только самое последнее значение, поэтому, если Binding(), .Source, .SetBinding() все записали в TraceSource (включая возможные пустые строки), вы можете не увидеть ожидаемого сообщения.) Также попробуйте ведение журнала на подробном уровне, возможно, оно записывается как предупреждение в режиме выпуска. Моим следующим шагом было бы разобрать этот объект Binding и посмотреть, как он вызывает TraceSource. - person MatthewMartin; 26.11.2014
comment
Спасибо, но я нашел решение и опубликовал его! я знаю, что ошибка просто держит последнюю ошибку привязки, но это был просто упрощенный образец! В моем проекте я использую метод stringBuilder с методом append() для хранения всех ошибок привязки, и я использую Assert.That(sb.ToString(), Is.Empty, sb.ToString())... если это может кому-то помочь! - person Heyjee; 26.11.2014