[MVVM] 8.유닛 테스트와 MVVM, UI 상호작용을 테스트하는 방법 (예 MSTest와 NUnit)

소프트웨어 개발에서 유닛 테스트는 코드의 안정성을 보장하는 핵심 기술 중 하나입니다. C# WPF 애플리케이션을 개발할 때 MVVM (Model-View-ViewModel) 아키텍처를 적용하면 비즈니스 로직과 UI를 분리할 수 있어, 유닛 테스트를 작성하기 용이합니다. 이 글에서는 MVVM 아키텍처에 기반한 C# WPF 애플리케이션에서 유닛 테스트를 작성하는 방법, MSTest와 NUnit 프레임워크를 사용하는 방법에 대해 자세히 설명하겠습니다.

1. MVVM 아키텍처 이해하기

MVVM은 Model-View-ViewModel의 약자로, WPF와 같은 UI 프레임워크에서 데이터와 사용자 인터페이스를 분리하는 데 유용한 아키텍처입니다. 각각의 구성 요소는 다음과 같은 역할을 합니다:

  • Model: 데이터 및 비즈니스 로직을 포함하며, 애플리케이션의 핵심 기능을 구현합니다.
  • View: 사용자 인터페이스를 정의하며, 사용자에게 정보를 보여주고 사용자 입력을 수집합니다.
  • ViewModel: Model과 View 간의 상호작용을 중재합니다. 데이터 바인딩을 통해 View에 Model의 데이터를 전달하고, View의 사용자 입력을 Model에 전달합니다.

2. 유닛 테스트란 무엇인가?

유닛 테스트는 개별 구성 요소, 즉 유닛의 기능을 검증하는 테스트입니다. 일반적으로 클래스나 메서드와 같은 단위를 테스트하며, 각 유닛이 기대하는 대로 동작하는지 확인합니다. 유닛 테스트의 주요 장점은 코드의 리팩토링이나 변경에도 불구하고 기존 기능이 유지되도록 보장하는 것입니다.

3. 왜 MVVM 패턴을 사용하는가?

MVVM 패턴은 데이터 바인딩, 커맨드 등의 기능 덕분에 테스트 용이성을 극대화합니다. ViewModel은 Model에서 데이터를 가져오고, 사용자 입력이 있을 때 그 데이터를 업데이트하는 로직을 가지고 있습니다. 이러한 구조 덕분에 UI와 비즈니스 로직이 완전히 분리되어 유닛 테스트가 수월합니다.

4. MSTest와 NUnit 소개

MSTest와 NUnit는 C#에서 가장 널리 사용되는 두 가지 유닛 테스트 프레임워크입니다. 두 프레임워크의 주요 특징은 다음과 같습니다:

  • MSTest: Microsoft에서 제공하는 테스트 프레임워크로, Visual Studio와의 통합이 쉬워서 접근성이 높습니다.
  • NUnit: 독립적으로 발전해온 테스트 프레임워크로, 다양한 기능과 유연성을 제공합니다. 빌드 자동화 도구와 쉽게 통합할 수 있습니다.

5. 예제: MVVM 구조와 유닛 테스트 구현

5.1. 애플리케이션 구조

간단한 WPF 애플리케이션을 상상해보겠습니다. 사용자로부터 이름을 입력받아 인사 메시지를 표시하는 애플리케이션을 만들겠습니다. 이 애플리케이션은 MVVM 아키텍처를 따르며, 다음과 같은 구조를 가집니다:

  • Model: 사용자의 이름 데이터를 저장합니다.
  • View: 사용자 인터페이스를 정의합니다.
  • ViewModel: 사용자 입력을 처리하고 모델과 상호작용합니다.

5.2. Model 클래스

public class Person
{
    public string Name { get; set; }
}

5.3. ViewModel 클래스

using System.ComponentModel;
using System.Windows.Input;

public class MainViewModel : INotifyPropertyChanged
{
    private Person _person;
    public string Greeting => $"안녕하세요, {_person.Name}!";

    public string Name
    {
        get => _person.Name;
        set
        {
            if (_person.Name != value)
            {
                _person.Name = value;
                OnPropertyChanged(nameof(Name));
                OnPropertyChanged(nameof(Greeting));
            }
        }
    }

    public MainViewModel()
    {
        _person = new Person();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

5.4. View (XAML)

<Window x:Class="MyApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="인사하기" Height="200" Width="300">
    <Grid>
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
        <TextBlock Text="{Binding Greeting}" Margin="0,30,0,0" />
    </Grid>
</Window>

5.5. MSTest를 사용한 유닛 테스트

이제 ViewModel을 테스트하기 위한 유닛 테스트를 작성해보겠습니다. MSTest를 사용하여 이름을 변경하고 인사 메시지가 올바르게 업데이트되는지 테스트합니다.

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class MainViewModelTests
{
    [TestMethod]
    public void Name_WhenChanged_UpdatesGreeting()
    {
        // Arrange
        var viewModel = new MainViewModel();
        
        // Act
        viewModel.Name = "홍길동";
        
        // Assert
        Assert.AreEqual("안녕하세요, 홍길동!", viewModel.Greeting);
    }
}

5.6. NUnit을 사용한 유닛 테스트

NUnit을 사용하여 같은 기능을 테스트해보겠습니다. NUnit을 사용하면 테스트 메서드에 [Test] 특성을 추가하는 방식으로 테스트를 정의합니다.

using NUnit.Framework;

[TestFixture]
public class MainViewModelNUnitTests
{
    [Test]
    public void Name_WhenChanged_UpdatesGreeting()
    {
        // Arrange
        var viewModel = new MainViewModel();
        
        // Act
        viewModel.Name = "홍길동";
        
        // Assert
        Assert.AreEqual("안녕하세요, 홍길동!", viewModel.Greeting);
    }
}

6. UI 상호작용 테스트

유닛 테스트는 주로 비즈니스 로직을 테스트하지만, UI와의 상호작용도 테스트할 수 있습니다. UI 테스트는 일반적으로 통합 테스트 도구를 사용하여 수행됩니다. 세부적으로, UI 테스트 도구로는 Appium, TestStack.White, Selenium 등이 있습니다. 이러한 도구들은 실제로 UI를 조작하여 테스트를 실행합니다.

6.1. UI 테스트 도구 선택

WPF 애플리케이션의 UI를 테스트하기 위해 TestStack.White를 사용할 수 있습니다. TestStack.White는 .NET 애플리케이션의 UI를 쉽고 직관적으로 테스트할 수 있도록 해주는 툴킷입니다.

6.2. TestStack.White로 UI 테스트

다음은 TestStack.White를 사용하여 UI 테스트를 수행하는 간단한 예제입니다:

using System.Threading;
using TestStack.White;
using TestStack.White.UIItems.WindowItems;

[TestClass]
public class MainWindowUiTests
{
    private Application _application;

    [TestInitialize]
    public void Setup()
    {
        _application = Application.Launch("MyApp.exe");
        Thread.Sleep(2000); // 앱이 로드될 때까지 대기
    }

    [TestCleanup]
    public void Cleanup()
    {
        _application.Close();
    }

    [TestMethod]
    public void InputName_UpdatesGreeting()
    {
        var window = _application.GetWindow("인사하기");
        var textBox = window.Get("nameTextBox");
        var greetingLabel = window.Get

7. 결론

유닛 테스트는 C# WPF 애플리케이션에서 MVVM 아키텍처를 채택할 때 매우 핵심적인 요소입니다. 테스트를 통해 비즈니스 로직의 변화에도 불구하고 안정성을 유지할 수 있습니다. MSTest와 NUnit은 다양한 요구에 따라 선택할 수 있는 훌륭한 테스트 프레임워크이며, UI 상호작용 테스트를 통해 사용자 경험을 보장할 수 있습니다. 이러한 모든 작업은 궁극적으로 더 안정적이고 유지보수하기 쉬운 애플리케이션 개발로 이어질 것입니다.

이 글이 MVVM 아키텍처와 유닛 테스트에 대한 이해를 높이는 데 도움이 되었기를 바랍니다. 앞으로 더 나은 테스트 주도 개발(TDD) 환경을 구축하는 데 기여할 수 있는 여러 사례들을 만들어 나가시길 바랍니다.