보라코딩

Day 19, C# _ Unit Test 본문

개발자가 되었다?

Day 19, C# _ Unit Test

new 보라 2023. 9. 11. 18:35

단위테스트

  • 애플리케이션 안에 있는 개별적인 코드 단위가 의도한 대로 작동하는지 확인하는 행위
  • 개별적인 기능이 의도한대로 작동하는지 확인하는 행위

 

단위테스트 사용하는 이유

  • 원하는 부분만 테스트해서 결과를 빠르게 볼 수 있음
  • 리팩토링을 안정적으로 가능
  • 단위테스트 실패 지점에서 코드의 문제점 빠르게 찾을 수 있음

 

테스트코드 작성 표현방식 (선택)

  • given - when -then 패턴
    1. given : 테스트를 위해 준비하는 과정 / 테스트에 사용하는 값 정의
    2. when : 테스트하고자 하는 기능 실행
    3. then : 기능 실행 후 결과를 검증
@Test
@Displayname("자동차는 명령을 받은만큼 이동거리가 증가한다")
void car_moves_as_order(){
  // given (주어진 값)
  int orderCount = 10;
  Car car = new Car();

  // when (기능 작동)
  car.moveAsOrdered(orderedCount);
  int distanceResult = car.getPosition();

  // then (기능 작동 후 검증)
  assertThat(distanceResult).isEqualTo(orderCount);

 

단위테스트 꿀팁

  • @ParameterizedTest 사용해서 여러 값을 테스트하자!
@ParameterizedTest
@ValueSource(ints = {-1, 0, 11, 12}
@DisplayName("자동차 이동")
void throws_exception_when_order_count_invalid(int givenOrderCount){
  // given
  String exceptedErrorMessage = "이동 거리는 1 이상 10 이하의 수만 가능";
  Car car = new Car();

  // when & then
  assertThatThrownBy(() -> car.moveAsOrdered(givenOrderCount)
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessageContaining(expectedErrorMessage);

 

First 원칙

  • 효율적이고 좋은 단위 테스트를 위한 5가지 요소로 이뤄진 규칙
    • Fast : 단위테스트는 빨라야 한다.
    • Independent : 테스트는 독립적으로 동작해야 한다. 이전 테스트에 영향을 받으면 실패 원인을 찾기 어렵다.
    • Repeatable : 어떤 상황에서든 예상한 대로 테스트 결과가 나와야한다.
    • Self-Validating : 출력 혹은 로그가 아닌 테스트 자체적으로 결과가 나와야한다.
    • Timely : 적시에 테스트를 철저하게 작성해야한다.

 

TDD(Test Driven Development) : 테스트 주도 개발

  • 수정 요청 시, 리팩토링을 훨씬 안정적으로 할 수 있음
  • 스펙 문서 기능 (파라미터, 반환값 등 스펙 확인)
  • 디자인 개선 효과
  • 디버깅 시간 감소
  • 프로젝트 생산성 향샹 (비지니스 로직의 허점을 사전에 발견)

 

테스트코드 실습

 

Reservation.cs

namespace TestNinja.Fundamentals
{
    public class Reservation
    {
        public User MadeBy { get; set; }

        public bool CanBeCancelledBy(User user)
        {
            return (user.IsAdmin || MadeBy == user);
        }

    }

    public class User
    {
        public bool IsAdmin { get; set; }
    }
}

 

ReservationTests.cs

using TestNinja.Fundamentals;

namespace TestNinja.UnitTests
{
    public class ReservationTests
    {
        [SetUp]
        public void Setup()
        {
        }

        [Test]
        public void CanBeCancelledBy_Scenario_ExpectedBehavior()
        {
            // Arrange
            var reservation = new Reservation();

            // Act
            var result = reservation.CanBeCancelledBy(new User { IsAdmin = true });

            // Assert
            Assert.IsTrue(result);
        }

        [Test]
        public void CanBeCancelledBy_SameUserCancellingTheReservation()
        {
            var user = new User();
            var reservation = new Reservation { MadeBy = user };

            var result = reservation.CanBeCancelledBy(user);

            Assert.IsTrue(result);
        }

        [Test]
        public void CanBeCacelledBy_AnotherUserCancellingReservation_ReturnFalse()
        {
            var reservation = new Reservation { MadeBy = new User() };

            var result = reservation.CanBeCancelledBy(new User());

            Assert.IsFalse(result);
        }
    }
}





계산기 테스트코드 작성하기

Calculator.cs

using System;
using System.Collections.Generic;

namespace TestNinja.Fundamentals
{
    public class Calculator
    {
        public int Add(int a, int b)
        {
            return a + b;
        }

        public int Subtract(int a, int b)
        {
            return a - b;
        }

        public int Multiply(int a, int b)
        {
            return a * b;
        }

        public int Divide(int a, int b)
        {
            if (b == 0)
                throw new ArgumentException("Divisor cannot be zero.");
            return a / b;
        }
    }
}

 

CalculatorTests.cs

using NUnit.Framework.Constraints;
using TestNinja.Fundamentals;

namespace TestNinja.UnitTests
{
    public class CalculatorTests
    {
        [SetUp]
        public void Setup()
        {
        }


        [Test] // 더하기
        public void Plus()
        {
            // Arrange
            int a = 2; int b = 3;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Add(a, b);

            // Assert
            Assert.AreEqual(5, result);
        }


        [Test] // 빼기
        public void Substract()
        {
            // Arrange
            int a = 5; int b = 3;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Subtract(a, b);

            // Assert
            Assert.AreEqual(2, result);
        }


        [Test] // 곱하기
        public void Multiply()
        {
            // Arrange
            int a = 2; int b = 3;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Multiply(a, b);

            // Assert
            Assert.AreEqual(6, result);
        }


        [Test] // 나누기
        public void Divide()
        {
            // Arrange
            int a = 6; int b = 3;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Divide(a, b);

            // Assert
            Assert.AreEqual(2, result);
        }


        [Test] // 0으로 나누기
        public void DivideByZero()
        {
            // Arrange
            int a = 5; int b = 0;

            // Act
            Calculator calculator = new Calculator();

            // Assert
            Assert.Throws<ArgumentException>(() => calculator.Divide(a, b));
        }


        [Test] // 음수 빼기
        public void Subtrict_minus()
        {
            // Arrange
            int a = -1; int b = -2;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Subtract(a, b);

            // Assert
            Assert.AreEqual(1, result);
        }


        [Test] // 0 곱하기
        public void MultiplyByZero()
        {
            // Arrange
            int a = 811; int b = 0;

            // Act
            Calculator calculator = new Calculator();
            int result = calculator.Multiply(a, b);

            // Assert
            Assert.AreEqual(0, result);
        }


        [Test] // 복잡한 계산
        public void ComplicatedCalculator()
        {
            // Arrange
            int a = 2; int b = 3; int c = 4;

            // Act
            Calculator calculator = new Calculator();
            int result1 = calculator.Multiply(a, b);
            int result2 = calculator.Divide(c, a);
            int result3 = calculator.Subtract(result1, result2);

            // Assert
            Assert.AreEqual(4, result3);
        }
    }
}

'개발자가 되었다?' 카테고리의 다른 글

Day 21, EF Core  (0) 2023.09.13
Day 20, C#  (0) 2023.09.12
Day 18, C# (DB 연동_MySQL)  (0) 2023.09.08
Day 17, C# (WPF로 카카오 API 연동)  (0) 2023.09.07
Day 16, C#  (0) 2023.09.07