Entity-ORM이 발생시키는 SQL로그를 추적하는 방법을 살펴보자
어플리케이션 로그설정 클래스작성
using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; //Nuget을 통해 다운로드받는다. using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Logging.Debug; namespace accountapi.Config { public class LogSettings { public static readonly LoggerFactory ConsoleLogger = new LoggerFactory(new[] { new ConsoleLoggerProvider((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Debug, true) }); public static readonly LoggerFactory DebugLogger = new LoggerFactory(new[] { new DebugLoggerProvider((_, logLevel) => logLevel >= LogLevel.Debug) }); } }
Microsoft.Extensions.Logging 은 여러가지 외부 로그장치와 연결시킬수 있는 일괄적인 방법을 제공합니다.
여기서는 ConsoleLogger와 DebugLogger 두가지를 셋팅하고 Xunit에서는 DebugLogger을 사용해보겠습니다.
Xunit에서 DebugLogger을 사용하는이유는, 테스트 대상이되는 외부APP에서 사용된 ConsoleLogger의경우 표시가되지
않기때문입니다.
DBContext에 로그연결하기
var builder = new DbContextOptionsBuilder<AccountContent>() .UseLoggerFactory(LogSettings.DebugLogger) //Entity ORM의 로그셋팅 .UseMySql(AccountControlerTest.ConnectionString); var context = new AccountContent(builder.Options);
DBContext에 로깅이 설정이되어 이제부터 SQL문 파악이 가능해집니다.
유닛테스트 실행
ORM을 통해 DB를 제어하는 몇가지 유닛테스트가 셋팅되어 있으며 테스트를 실행할시에는 유효검사가 성공하는 메시지만 볼수가 있습니다.
여기서 유닛 테스트시 사용되는 SQL문을 심도있게 분석하고자 한다면 선택한 테스트 디버그를 실행합니다.
유닛테스트 디버그
앞장에서 설명한 Entity-ORM에서 낙관성 동시성 제어를 사용하였고, 의도적으로 동시 수정을 하여
DbUpdateConcurrencyException을 발생하게 한코드입니다.
ORM을 사용하였기때문에 SQL문을 단 한줄도 작성한적이 없으나, 로직코드와 실제 작동하는 SQL문을 같이 비교할수가 있습니다.
Entity-ORM에서는 동시성 제어를 위해 ConcurrencyCheck라는 어노테이션만 사용이됩니다.
[ConcurrencyCheck]
public
string
LastName {
get
;
set
; }
여기서 중요한것은 동시성 제어 어노테이션이 , 왜 위와같은 SQL문을 수행하는지 이해하고 파악 할수 있다란것과
SQL문없이 몇줄의 OOP 코드로만 DB Concurrency Write문제를 유발시킬수 있다란것입니다.
유닛테스트 결과확인
유닛테스트는 대부분 유효검증을하는것만으로 충분하지만, 검증에 사용된 데이터를 직접 확인하고자 한다면
모든 객체를 Json형태로 표현할수 있는 OutputJson과 같은 유틸리티 함수를 만들어 사용하는것입니다.
ITestOutputHelper는 xUnit에서 제공되는 기본 인터페이스이며 표준적인 유닛테스트 결과처리에대해 지원을 합니다.
생성자에 셋팅을 함으로, 의존성주입으로 인해 사용가능해 집니다.
public class AccountControlerTest { private readonly ITestOutputHelper output; public AccountControlerTest(ITestOutputHelper output) { this.output = output; InitContext(); } protected void OutPutJson(Object obj) { output.WriteLine("{0}", JsonConvert.SerializeObject(obj, Formatting.Indented)); } [Fact] public void TestUserActive() { bool expected = false; var controller = new AccountControler(_accountService); User result = controller.GetUserByid(1); // 대상을 조회함 OutPutJson(result); //대상을 Print함 Assert.Equal(expected, result.IsSocialActive); //대상 유효검사함 } }
여기서 ORM의 특징하나를 더 얻게되었습니다.
DB조회 / 출력 / 검증기능 3가지를 각각 한줄의 코드면 충분하다란것입니다.
참고자료
- MSDN 공식문서 : https://docs.microsoft.com/ko-kr/ef/core/saving/concurrency
- 동시성에 대한 용어정리 : 동시성 이해를 위한 용어정리