-
Notifications
You must be signed in to change notification settings - Fork 17
250916_11_유아리 #149
base: student/11_유아리
Are you sure you want to change the base?
250916_11_유아리 #149
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Summary by CodeRabbit
Walkthrough두 콘솔 앱과 테스트 프로젝트를 추가하고, DTO·DataSource·Mapper·Model·Repository·공용(Result/Response) 타입을 신설해 HTTP 호출 → DTO 역직렬화 → 매핑 → Result 반환 흐름을 구현했다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller
participant Repo as PokemonRepository
participant DS as PokemonApiDataSource
participant HTTP as HttpClient
participant JSON as Newtonsoft.Json
Caller->>Repo: GetPokemonByNameAsync(name)
alt name is null/whitespace
Repo-->>Caller: Result.Error(InvalidInput)
else valid name
Repo->>DS: GetPokemonAsync(name)
DS->>HTTP: GET /pokemon/{name}
HTTP-->>DS: HttpResponse(status, headers, json)
DS->>JSON: Deserialize -> PokemonDto
DS-->>Repo: Response<PokemonDto>(status, headers, body)
alt status == 200
Repo->>Repo: dto.ToModel()
Repo-->>Caller: Result.Success(Pokemon)
else status == 404
Repo-->>Caller: Result.Error(NotFound)
else
Repo-->>Caller: Result.Error(UnknownError)
end
end
opt exception
Repo-->>Caller: Result.Error(UnknownError)
end
sequenceDiagram
autonumber
actor Caller
participant Repo as StationRepository
participant DS as StationApiDataSource
participant HTTP as HttpClient
participant JSON as Newtonsoft.Json
Caller->>Repo: GetStationAsync(stationName)
alt stationName is null/whitespace
Repo-->>Caller: Result.Error(InvalidInput)
else
Repo->>DS: GetStationAsync(stationName)
DS->>HTTP: GET /.../{encodedStationName}
HTTP-->>DS: HttpResponse(status, headers, json)
DS->>JSON: Deserialize -> StationDto
DS-->>Repo: Response<StationDto>(status, headers, body)
alt status == 200
Repo->>Repo: dto.ToModels()
Repo-->>Caller: Result.Success(List<Station>)
else status == 404
Repo-->>Caller: Result.Error(NotFound)
else
Repo-->>Caller: Result.Error(UnknownError)
end
end
opt exception
Repo-->>Caller: Result.Error(NetworkError)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @yooari88, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
이 Pull Request는 CshapStudy.DtoMapper와 CshapStudy.realtimeStationArrival라는 두 개의 새로운 C# 프로젝트를 도입합니다. 이 프로젝트들은 외부 API 데이터를 처리하는 모범 사례를 보여주며, DTO(Data Transfer Object) 사용, 도메인 모델로의 변환을 위한 전용 매퍼, 그리고 명시적인 성공/실패 처리를 위한 사용자 정의 Result 타입을 포함하는 견고한 리포지토리 패턴을 구현합니다. 이러한 변경 사항은 C# 애플리케이션에서 데이터 무결성, 관심사 분리 및 오류 관리를 개선하는 것을 목표로 합니다.
Highlights
- 새로운 프로젝트 추가: CshapStudy.DtoMapper 및 CshapStudy.realtimeStationArrival 두 개의 새로운 C# 프로젝트가 추가되었습니다.
- Result 타입 도입: 성공과 실패를 명시적으로 처리하기 위한 제네릭 Result<TData, TError> 추상 레코드와 Success, Error 봉인 레코드가 구현되었습니다.
- DTO 및 매퍼 구현: 외부 API 응답을 위한 DTO(Data Transfer Object)와 이를 도메인 모델로 변환하는 전용 매퍼(Mapper)가 PokemonDto 및 StationDto에 대해 각각 추가되어 데이터 무결성과 관심사 분리를 강화했습니다.
- API 데이터 소스: PokeAPI 및 서울시 지하철 실시간 도착 정보 API와 연동하는 PokemonApiDataSource 및 StationApiDataSource가 구현되었습니다.
- 리포지토리 패턴 적용: 데이터 접근 로직을 추상화하고 Result 타입을 활용하여 오류를 처리하는 PokemonRepository 및 StationRepository가 도입되었습니다.
- 단위 테스트 추가: CsharpStudy.DtoMapper.Tests 프로젝트에 PokemonMapper 및 PokemonRepository에 대한 기본적인 단위 테스트가 작성되어 기능 검증 및 오류 처리 로직을 확인합니다.
- TIL (Today I Learned) 기록: DTO, Nullable 타입, 매퍼, 그리고 Result 패턴을 통한 오류 처리에 대한 학습 내용이 TIL 문서로 추가되었습니다.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in pull request comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
이 PR은 PokeAPI와 서울시 지하철 도착 정보 API를 사용하여 데이터를 가져오고 처리하는 두 개의 새로운 프로젝트(CshapStudy.DtoMapper, CshapStudy.realtimeStationArrival)를 추가합니다. 전반적으로 DTO, Mapper, Repository, Result 타입을 사용하는 구조는 잘 설계되었습니다. 하지만 몇 가지 중요한 개선점이 필요합니다.
주요 문제점들은 다음과 같습니다:
- 보안: API 호출 시 URL 인코딩이 누락되어 URL 주입에 취약하며,
http를 사용하는 API가 있습니다. - 정확성: JSON 역직렬화 시
System.Text.Json과Newtonsoft.Json의 어트리뷰트가 혼용되어 오작동할 수 있으며, null을 허용하지 않는 DTO 속성들이 API 응답에 따라 런타임 에러를 유발할 수 있습니다. - 프로젝트 구조: 일부 테스트 관련 파일들이 잘못된 프로젝트 폴더에 포함되어 있으며, 빌드 환경에 종속적인 하드코딩된 파일 경로가 프로젝트 설정에 포함되어 있습니다.
- 예외 처리: 예외 처리가 너무 광범위하여(catch-all), 오류의 원인을 파악하기 어렵게 만듭니다.
아래에 각 파일에 대한 구체적인 리뷰 의견을 남겼습니다. 테스트 코드 작성에 어려움을 겪으셨다고 하셨는데, 이번 리뷰가 테스트 코드뿐만 아니라 전반적인 코드 품질을 높이는 데 도움이 되기를 바랍니다.
| <Reference Include="JetBrains.ReSharper.TestRunner.Merged"> | ||
| <HintPath>..\..\..\..\..\..\Applications\Rider.app\Contents\lib\ReSharperHost\TestRunner\netcoreapp3.0\JetBrains.ReSharper.TestRunner.Merged.dll</HintPath> | ||
| </Reference> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace CshapStudy.realtimeStationArrival.DTOs; | ||
| using Newtonsoft.Json; | ||
| using System.Collections.Generic; | ||
|
|
||
| public class StationDto | ||
| { | ||
| [JsonPropertyName("errorMessage")] | ||
| public ErrorMessage ErrorMessage { get; set; } | ||
|
|
||
| [JsonPropertyName("realtimeArrivalList")] | ||
| public List<RealtimeArrival> RealtimeArrivalList { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 파일에서는 System.Text.Json.Serialization.JsonPropertyName 어트리뷰트를 사용하고 있지만, StationApiDataSource에서는 Newtonsoft.Json을 사용하여 역직렬화를 수행합니다. 사용하는 라이브러리에 맞는 [JsonProperty("...")] 어트리뷰트로 변경해야 합니다. 그렇지 않으면 속성이 올바르게 매핑되지 않아 런타임 오류가 발생할 수 있습니다. 또한, using Newtonsoft.Json; 구문은 파일 상단으로 옮기는 것이 좋습니다.
using Newtonsoft.Json;
using System.Collections.Generic;
namespace CshapStudy.realtimeStationArrival.DTOs;
public class StationDto
{
[JsonProperty("errorMessage")]
public ErrorMessage ErrorMessage { get; set; }
[JsonProperty("realtimeArrivalList")]
public List<RealtimeArrival> RealtimeArrivalList { get; set; }|
|
||
| public class StationApiDataSource : IStationApiDataSource | ||
| { | ||
| private const string BaseUrl ="http://swopenapi.seoul.go.kr/api/subway/sample/json/realtimeStationArrival/0/5/"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public int Status { get; set; } | ||
|
|
||
| [JsonPropertyName("code")] | ||
| public string Code { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| catch (Exception) | ||
| { | ||
| return new Result<List<Station>, StationError>.Error(StationError.NetworkError); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch (Exception)은 모든 예외를 잡기 때문에 너무 광범위합니다. HttpRequestException과 같은 특정 예외를 잡아 NetworkError로 처리하는 등 오류 유형을 더 세분화하는 것이 좋습니다. 또한, 예외가 발생했을 때 어떤 오류인지 알 수 있도록 예외 정보를 로깅하는 것이 좋습니다.
catch (HttpRequestException e)
{
// TODO: Log exception e
return new Result<List<Station>, StationError>.Error(StationError.NetworkError);
}
catch (Exception e)
{
// TODO: Log exception e
return new Result<List<Station>, StationError>.Error(StationError.UnknownError);
}| public enum PoKemonError | ||
| { | ||
| NetWorkError, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @@ -0,0 +1,39 @@ | |||
| namespace CshapStudy.DtoMapper.Models; | |||
|
|
|||
| public record Pokemon(String Name, String ImageUrl); | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| public interface IStationRepository | ||
| { | ||
| Task<Result<List<Station>,StationError>> GetStationAsync(String stationName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public class Response<T> | ||
| { | ||
| public int StatusCode { get; set; } | ||
| public object Headers { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| await repository.GetPokemonByNameAsync("serialization-error"); | ||
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
43번째 줄에서 await의 결과가 변수에 할당되지 않고 무시되고 있습니다. 따라서 44번째 줄의 Assert는 이전 호출("timeout")의 결과인 errorResult를 다시 검증하고 있습니다. 이는 테스트 로직의 버그입니다.
result = await repository.GetPokemonByNameAsync("serialization-error");
errorResult = result as Result<Pokemon, PoKemonError>.Error;
Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (39)
CshapStudy.DtoMapper/Program.cs (1)
5-7: Main 인자 미사용 — 시그니처 단순화 권장args를 쓰지 않으므로 불필요한 인자를 제거하면 가독성이 좋아집니다.
- static void Main(string[] args) + static void Main()CshapStudy.DtoMapper/Models/Pokemon.cs (2)
3-3: BCL 타입 표기 대신 키워드 사용 권장(string)C# 컨벤션에 따라 String 대신 string을 사용하면 일관성이 좋아집니다.
-public record Pokemon(String Name, String ImageUrl); +public record Pokemon(string Name, string ImageUrl);
4-39: 대량의 주석 처리된 대안 구현 제거 제안주석 블록이 길어 가독성을 해치고 유지보수에 혼선을 줍니다. 필요하다면 Git 히스토리로 대체 가능하므로 삭제를 권장합니다.
-// public class Pokemon -// { -// public string Name { get; set; } -// public string Imageurl { get; set; } -// public Pokemon(string name, string imageUrl) -// { -// Name = name; -// Imageurl = imageUrl; -// } -// protected bool Equals(Pokemon other) -// { -// return Name == other.Name && Imageurl == other.Imageurl; -// } -// public override bool Equals(object? obj) -// { -// if(obj is null) return false; -// if (ReferenceEquals(this, obj)) return true; -// if (obj.GetType() != this.GetType()) return false; -// return Equals((Pokemon)obj); -// } -// public override int GetHashCode() -// { -// return HashCode.Combine(Name, Imageurl); -// } -// public override string ToString() -// { -// return $"{nameof(Name)}: {Name}, {nameof(Imageurl)}: {Imageurl}"; -// } -// }CsharpStudy.2hakgi/TIL/2025_0916 (1)
7-7: 오탈자/표현 교정 제안학습 메모이지만 레포에 남는 문서이므로 간단히 교정하면 좋겠습니다.
-에러처리의 기본은 try-cath +에러처리의 기본은 try-catch -rutime에 터지는것만 해준다. +runtime에 터지는 것만 다룬다. -길게 쓸꺼를 짧게 쓰는것을 레코드 g +길게 쓸 내용을 짧게 표현하려면 record를 사용한다.Also applies to: 9-9, 17-17
CshapStudy.realtimeStationArrival/Program.cs (1)
5-7: Main 인자 미사용 — 시그니처 단순화 권장args 미사용이므로 제거를 제안합니다.
- static void Main(string[] args) + static void Main()CsharpStudy.2hakgi/TIL/2025_0915 (1)
5-6: 간단한 문장 교정(가독성/오탈자)짧게 손보면 이해가 더 쉬워집니다.
-DTO는 JSON을 그대로 담는 객체 변환하는게 mapper (방어수단) +DTO는 JSON을 그대로 담는 객체이고, 변환은 mapper가 담당한다(방어 수단). -모든 필드가 Nullable인 것은 안터지려고 +모든 필드를 Nullable로 두는 접근은 권장하지 않는다. -안넣어도 될떄는 Mapper도 필요없다. +안 넣어도 될 때는 Mapper도 필요 없다.Also applies to: 14-14
CshapStudy.realtimeStationArrival/Common/Result.cs (2)
5-7: 프로퍼티 이름 PascalCase로 정리(Data/Error)레코드 주 생성자 매개변수가 그대로 소문자 프로퍼티로 노출됩니다. 관례상 PascalCase로 두는 편이 좋습니다.
- public sealed record Success(TData data) : Result<TData, TError>; + public sealed record Success(TData Data) : Result<TData, TError>; - - public sealed record Error(TError error) : Result<TData, TError>; + public sealed record Error(TError Error) : Result<TData, TError>;
3-8: 중복 타입 통합 제안(Result<TData,TError> 공유화)DtoMapper 프로젝트에도 동일한 Result 정의가 있는 것으로 보입니다. 공통 프로젝트로 분리하거나 링크 파일로 단일 소스로 관리하면 드리프트를 막을 수 있습니다.
CshapStudy.realtimeStationArrival/Models/Station.cs (1)
3-16: 값 동등성/불변성 강화 위해 record 전환 고려도메인 값 객체 성격이라면 record로 간결하게 표현할 수 있습니다.
-public class Station -{ - public string TrainLineName { get; } - public string DestinationStation { get; } - public string CurrentLocationMessage { get; } - public string SubwayLineId { get; } - - public Station(string trainLineName, string destinationStation, string currentLocationMessage, string subwayLineId) - { - TrainLineName = trainLineName; - DestinationStation = destinationStation; - CurrentLocationMessage = currentLocationMessage; - SubwayLineId = subwayLineId; - } -} +public sealed record Station( + string TrainLineName, + string DestinationStation, + string CurrentLocationMessage, + string SubwayLineId +);CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
9-13: DTO null 허용성 정합성API 응답 누락 시
ErrorMessage/RealtimeArrivalList가 null이 될 수 있습니다. 현재 비-null 참조형으로 선언되어 있어 경고/런타임 NRE 위험이 있습니다. nullable로 바꾸세요.- public ErrorMessage ErrorMessage { get; set; } + public ErrorMessage? ErrorMessage { get; set; } - public List<RealtimeArrival> RealtimeArrivalList { get; set; } + public List<RealtimeArrival>? RealtimeArrivalList { get; set; }CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
68-286: DTO 공개 범위 축소 고려DTO와 중첩 타입이 모두 public입니다. 외부 노출이 불필요하다면
internal로 축소해 API 표면을 줄이세요.-public class PokemonDto +internal class PokemonDto(다른 DTO들도 동일 원칙 적용)
CshapStudy.DtoMapper/CshapStudy.DtoMapper.csproj (1)
4-8: 라이브러리 성격이면 출력 형식을 Library로이 프로젝트가 테스트에서 참조되는 라이브러리라면 Exe 대신 Library가 적합합니다.
- <OutputType>Exe</OutputType> + <OutputType>Library</OutputType>CsharpStudy.DtoMapper/CsharpStudy.DtoMapper.csproj (1)
4-7: 단일 타깃이면 TargetFrameworks → TargetFramework사소하지만 불필요한 복수형 속성 사용입니다.
- <TargetFrameworks>net8.0</TargetFrameworks> + <TargetFramework>net8.0</TargetFramework>CsharpStudy.DtoMapper.Tests/CsharpStudy.DtoMapper.Tests.csproj (1)
4-9: 단일 타깃이면 TargetFrameworks → TargetFramework테스트 프로젝트도 단일 타깃이면 단수 속성이 더 명확합니다.
- <TargetFrameworks>net8.0</TargetFrameworks> + <TargetFramework>net8.0</TargetFramework>CshapStudy.DtoMapper/Repositories/IPokemonRepository.cs (1)
5-8: 취소 토큰 도입 및 에러 enum 네이밍 정렬IO 경로(repo→HTTP)에는
CancellationToken이 필요합니다. 또한 enum 리네임과 함께 시그니처를 정렬하세요.-public interface IPokemonRepository -{ - Task<Result<Models.Pokemon, PoKemonError>> GetPokemonByNameAsync(string pokemonName); -} +public interface IPokemonRepository +{ + Task<Result<Models.Pokemon, PokemonError>> GetPokemonByNameAsync(string pokemonName, CancellationToken cancellationToken = default); +}리포지토리 구현과 호출부 전반에 취소 전파 및
ConfigureAwait(false)(라이브러리 컨텍스트일 경우) 적용 여부를 함께 점검해 주세요.CshapStudy.realtimeStationArrival/DataSources/IStationApiDataSource.cs (1)
1-2: 취소 토큰 추가 + 입력 유효성 명세화 제안비동기 API 계약에
CancellationToken을 포함하면 상위 호출자가 타임아웃/취소를 제어할 수 있습니다. 또한stationName의 null/빈 문자열에 대한 계약(예: 예외 혹은 실패 반환)을 문서화하면 좋습니다.적용 예시:
+using System.Threading; public interface IStationApiDataSource { - Task<Response<StationDto>> GetStationAsync(string stationName); + Task<Response<StationDto>> GetStationAsync(string stationName, CancellationToken ct = default); }Also applies to: 8-8
CshapStudy.realtimeStationArrival/Repositories/IStationRepository.cs (1)
8-10: 메서드 시그니처 일관성(복수형, string 키워드, 취소 토큰)반환형이
List<Station>이므로 메서드명을 복수형으로,String→string으로 통일하고CancellationToken을 받도록 권장합니다. 또한 컬렉션은 변경 불가능 계약을 위해IReadOnlyList<Station>가 적합합니다.적용 예시:
+using System.Threading; ... -Task<Result<List<Station>,StationError>> GetStationAsync(String stationName); +Task<Result<IReadOnlyList<Station>, StationError>> GetStationsAsync(string stationName, CancellationToken ct = default);CsharpStudy.sln (1)
33-38: 프로젝트 이름 접두사 오탈자(CshapStudy vs CsharpStudy) 정리 권장새로 추가한 프로젝트들이
CshapStudy.*로 표기되어 기존CsharpStudy.*와 불일치합니다. 도메인 네이밍 일관성 유지를 위해 정규화(리네임)하는 것이 좋습니다. 리네임 시 csproj/namespace/폴더 경로까지 함께 정리 필요합니다.CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (1)
1-1: 취소 토큰 포함 및 Response.Headers 강타입화 고려
- API 계약에
CancellationToken을 추가하세요.- 별도 파일의
Response<T>.Headers가object로 선언되어 있어 사용성이 떨어집니다.IReadOnlyDictionary<string,string>등 강타입으로의 통일을 권장합니다(동일 솔루션의 realtimeStationArrival 쪽 구현과도 일치).적용 예시:
+using System.Threading; using CshapStudy.DtoMapper.DTOs; public interface IPokemonApiDataSource { - Task<Response<PokemonDto>> GetPokemonAsync(string pokemonName); + Task<Response<PokemonDto>> GetPokemonAsync(string pokemonName, CancellationToken ct = default); }Also applies to: 5-8
CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs (3)
22-26: 외부 네트워크 의존 테스트 제거 → 순수 매핑 단위 테스트로 전환현재 테스트가 PokeAPI 실서버에 의존합니다. 단위 테스트는 DTO→도메인 매핑만 검증하도록 DTO 인스턴스를 직접 만들어 검증하세요.
적용 예시:
- IPokemonApiDataSource dataSource = new PokemonApiDataSource(new HttpClient()); - Response<PokemonDto> response = await dataSource.GetPokemonAsync("ditto"); - PokemonDto pokemonDto = response.Body; - Pokemon pokemon = pokemonDto.ToModel(); - Assert.That(pokemon.Name, Is.EqualTo("ditto")); + var dto = new PokemonDto { Name = "ditto" }; + var pokemon = dto.ToModel(); + Assert.That(pokemon.Name, Is.EqualTo("ditto"));- IPokemonApiDataSource dataSource = new PokemonApiDataSource(new HttpClient()); - - Response<PokemonDto> response = await dataSource.GetPokemonAsync("ditto"); - PokemonDto pokemonDto = response.Body; - Pokemon pokemon = pokemonDto.ToModel(); - - Assert.That(pokemon.Name, Is.EqualTo("ditto")); + var dto = new PokemonDto(); // 모든 필드 null → 매퍼의 기본값 적용 검증 + var pokemon = dto.ToModel(); + Assert.Multiple(() => + { + Assert.That(pokemon.Name, Is.EqualTo("")); + Assert.That(pokemon.ImageUrl, Is.EqualTo("")); + });Also applies to: 33-41
20-20: 테스트 메서드명 오타
GET_Diito→GET_Ditto또는 의미 있는 명명(예:ToModel_Should_Map_Name).적용 예시:
- public async Task GET_Diito() + public void ToModel_Should_Map_Name()
1-10: 불필요 using 제거 및 네임스페이스 통일네임스페이스(
CsharpStudy.DtoTest.Mappers)가 테스트 프로젝트명과 불일치합니다. 또한System.Runtime,Repositories등 미사용 using을 정리하세요.적용 예시:
-using System.Net.Http; -using System.Collections.Generic; -using System.Runtime; -using System.Threading.Tasks; -using CshapStudy.DtoMapper.DataSource; using CshapStudy.DtoMapper.Mappers; -using CshapStudy.DtoMapper.Repositories; using NUnit.Framework; using CshapStudy.DtoMapper.DTOs; -using CshapStudy.DtoMapper.Models; -namespace CsharpStudy.DtoTest.Mappers; +namespace CsharpStudy.DtoMapper.Tests.Mappers;Also applies to: 12-12
CshapStudy.DtoMapper/Common/Result.cs (1)
3-8: 사소한 타이포 및 솔루션 내 중복 타입 정리 제안
- 이중 공백 및 제네릭 쉼표 뒤 공백 정리.
- 동일 솔루션에 유사
Result구현이 중복(realtimeStationArrival)되어 있습니다. 공용 프로젝트로 통합하거나 네이밍 구분 권장.적용 예시:
-public abstract record Result<TData,TError> +public abstract record Result<TData, TError> { public sealed record Success(TData data) : Result<TData, TError>; public sealed record Error(TError error) : Result<TData, TError>; }CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (1)
18-23: null 항목 필터링 및 공백 문자열 처리
RealtimeArrivalList에 null 항목이 포함되거나 필드가 공백만 있는 경우를 방어하면 매핑 안정성이 높아집니다.적용 예시:
- return dto.RealtimeArrivalList.Select(arrival => new Station( - trainLineName: arrival.TrainLineNm ?? "정보 없음", - destinationStation: arrival.BstatnNm ?? "정보 없음", - currentLocationMessage: arrival.ArvlMsg3 ?? "정보 없음", - subwayLineId: arrival.SubwayId ?? "정보 없음" - )).ToList(); + return dto.RealtimeArrivalList + .Where(arrival => arrival is not null) + .Select(arrival => new Station( + trainLineName: string.IsNullOrWhiteSpace(arrival!.TrainLineNm) ? "정보 없음" : arrival.TrainLineNm.Trim(), + destinationStation: string.IsNullOrWhiteSpace(arrival.BstatnNm) ? "정보 없음" : arrival.BstatnNm.Trim(), + currentLocationMessage: string.IsNullOrWhiteSpace(arrival.ArvlMsg3) ? "정보 없음" : arrival.ArvlMsg3.Trim(), + subwayLineId: string.IsNullOrWhiteSpace(arrival.SubwayId) ? "정보 없음" : arrival.SubwayId.Trim() + )) + .ToList();CshapStudy.DtoMapper/DataSource/Response.cs (1)
1-1: 불필요한 using 제거.DTOs 네임스페이스는 이 파일에서 사용되지 않습니다.
-using CshapStudy.DtoMapper.DTOs;CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
7-12: null 수신자 안전 처리.dto가 null이면 NRE가 발생합니다. 수신자를 nullable로 열고 기본값으로 매핑하세요.
- public static Models.Pokemon ToModel(this PokemonDto dto) + public static Models.Pokemon ToModel(this PokemonDto? dto) { return new Models.Pokemon( - Name: dto.Name ?? "", - ImageUrl: dto.Sprites?.Other?.OfficialArtwork?.FrontDefault ?? "" + Name: dto?.Name ?? string.Empty, + ImageUrl: dto?.Sprites?.Other?.OfficialArtwork?.FrontDefault ?? string.Empty ); }CshapStudy.realtimeStationArrival/Common/Response.cs (1)
5-7: 불변 객체로 만들어 의도 명확화.생성 후 수정되지 않도록 init 접근자를 고려하세요.
- public int StatusCode { get; set; } - public IReadOnlyDictionary<string,string> Headers { get; set; } - public T Body { get; set; } + public int StatusCode { get; init; } + public IReadOnlyDictionary<string,string> Headers { get; init; } + public T Body { get; init; }CshapStudy.realtimeStationArrival/Repositories/StationRepository.cs (2)
10-15: 주입 필드를 readonly로.의도치 않은 재할당을 방지하세요.
- private IStationApiDataSource _dataSource; + private readonly IStationApiDataSource _dataSource;
24-45: 예외 매핑을 구체화.모든 예외를 NetworkError로 취급하면 원인 파악이 어렵습니다. 네트워크 관련 예외만 NetworkError로, 그 외는 UnknownError로 분리하세요.
- catch (Exception) - { - return new Result<List<Station>, StationError>.Error(StationError.NetworkError); - } + catch (HttpRequestException) + { + return new Result<List<Station>, StationError>.Error(StationError.NetworkError); + } + catch (TaskCanceledException) + { + return new Result<List<Station>, StationError>.Error(StationError.NetworkError); + } + catch (Exception) + { + return new Result<List<Station>, StationError>.Error(StationError.UnknownError); + }CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs (3)
11-16: HttpClient 필드 readonly 및 불필요 using 제거.필드 불변 + 미사용 using 정리.
-using CshapStudy.realtimeStationArrival.Models; +using System.Linq; @@ - private HttpClient _httpClient; + private readonly HttpClient _httpClient;
18-33: 성공 응답에만 역직렬화하고, 실패 시 Body를 null로 둡니다.에러 응답을 역직렬화하면 예외가 발생해 상위 레이어 흐름 제어가 어려워집니다.
public async Task<Response<StationDto>> GetStationAsync(string stationName) { var response = await _httpClient.GetAsync($"{BaseUrl}{stationName}"); - var jsonString = await response.Content.ReadAsStringAsync(); + var jsonString = await response.Content.ReadAsStringAsync(); var headers = response.Headers.ToDictionary( header => header.Key, header => string.Join(",", header.Value) ); - return new Response<StationDto>( - statusCode: (int)response.StatusCode, - headers: headers, - body: JsonConvert.DeserializeObject<StationDto>(jsonString)! - ); + var body = response.IsSuccessStatusCode + ? JsonConvert.DeserializeObject<StationDto>(jsonString) + : default; + + return new Response<StationDto>( + statusCode: (int)response.StatusCode, + headers: headers, + body: body! + ); }
10-10: HTTPS 미지원으로 보입니다 — HTTP 유지하거나 백엔드 프록시로 보호하세요.
공식 문서·샘플에서 swopenapi.seoul.go.kr의 realtimeStationArrival는 HTTP만 예시되어 있어 HTTPS 엔드포인트가 확인되지 않습니다.
- 위치: CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs (라인 10, BaseUrl).
- 권장: 백엔드에서 HTTP로 API 호출 후 클라이언트와는 HTTPS로 통신(프록시) 사용.
- 대안: 서울 열린데이터포털에 HTTPS 지원 여부 최종 확인.
CshapStudy.DtoMapper/DataSource/PokemonApiDataSource.cs (3)
1-1: 불필요한 using 제거.사용되지 않는 System.Reflection.Metadata.Ecma335 참조입니다.
-using System.Reflection.Metadata.Ecma335;
10-21: 이중 슬래시 및 네이밍 정리._BaseUrl이 슬래시로 끝나는데 URL 조합 시 추가 슬래시를 붙여
//가 됩니다. 또한 변수/필드 네이밍 일관성을 유지하세요.- private const string _BaseUrl = "https://pokeapi.co/api/v2/pokemon/"; - private HttpClient _httpClient; + private const string BaseUrl = "https://pokeapi.co/api/v2/pokemon/"; + private readonly HttpClient _httpClient; @@ - var response = await _httpClient.GetAsync($"{_BaseUrl}/{pokemonName}"); - var jsonstring = await response.Content.ReadAsStringAsync(); + var response = await _httpClient.GetAsync($"{BaseUrl}{pokemonName}"); + var jsonString = await response.Content.ReadAsStringAsync();
22-32: 성공 응답에만 역직렬화.실패 응답 역직렬화는 예외를 유발할 수 있습니다.
- var headers = response.Headers.ToDictionary( + var headers = response.Headers.ToDictionary( header => header.Key, header => string.Join(",", header.Value) ); - return new Response<PokemonDto>( - statusCode: (int)response.StatusCode, - headers: headers, - body: JsonConvert.DeserializeObject<PokemonDto>(jsonstring)! - ); + var body = response.IsSuccessStatusCode + ? JsonConvert.DeserializeObject<PokemonDto>(jsonString) + : default; + + return new Response<PokemonDto>( + statusCode: (int)response.StatusCode, + headers: headers, + body: body! + );CshapStudy.DtoMapper/Repositories/PokemonRepository.cs (3)
10-15: 주입 필드를 readonly로.재할당 방지를 위해 readonly로 선언하세요.
- private IPokemonApiDataSource _dataSource; + private readonly IPokemonApiDataSource _dataSource;
27-33: Body null 안전 처리.200이라도 Body가 null일 수 있으므로 안전 매핑이 필요합니다.
- case 200: - var dto = response.Body; - Pokemon pokemon = dto.ToModel(); - return new Result<Pokemon, PoKemonError>.Success(pokemon); + case 200: + var pokemon = response.Body?.ToModel() ?? new Pokemon(string.Empty, string.Empty); + return new Result<Pokemon, PoKemonError>.Success(pokemon);
39-46: 사용하지 않는 예외 변수 제거.변수 e를 사용하지 않습니다.
- catch (Exception e) + catch (Exception) { return new Result<Pokemon, PoKemonError>.Error(PoKemonError.UnknownError); - - }CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs (1)
22-30: 테스트에서 외부 API 호출 제거 — Mock/Stub 사용 권장다음 테스트들이 PokemonApiDataSource(new HttpClient())로 실제 원격 호출에 의존하고 있어 플래키합니다. 네트워크/서드파티 장애로 실패할 수 있으니 테스트 더블(Stub/Mock) 또는 HttpClient 주입/모킹으로 교체하세요.
대상:
- CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs:22
- CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs:22
- CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs:33
권장 수정:
- IPokemonApiDataSource를 생성자 주입하고 테스트에서는 Fake/Mock 구현 주입
- 또는 HttpClient를 생성자 주입 후 Test용 HttpMessageHandler 또는 HttpClientFactory를 모킹하여 응답 제어
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (32)
CshapStudy.DtoMapper/Common/Result.cs(1 hunks)CshapStudy.DtoMapper/CshapStudy.DtoMapper.csproj(1 hunks)CshapStudy.DtoMapper/DTOs/PokemonDto.cs(1 hunks)CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs(1 hunks)CshapStudy.DtoMapper/DataSource/PokemonApiDataSource.cs(1 hunks)CshapStudy.DtoMapper/DataSource/Response.cs(1 hunks)CshapStudy.DtoMapper/Mappers/PokemonMapper.cs(1 hunks)CshapStudy.DtoMapper/Models/Pokemon.cs(1 hunks)CshapStudy.DtoMapper/Program.cs(1 hunks)CshapStudy.DtoMapper/Repositories/IPokemonRepository.cs(1 hunks)CshapStudy.DtoMapper/Repositories/PoKemonError.cs(1 hunks)CshapStudy.DtoMapper/Repositories/PokemonRepository.cs(1 hunks)CshapStudy.realtimeStationArrival/Common/Response.cs(1 hunks)CshapStudy.realtimeStationArrival/Common/Result.cs(1 hunks)CshapStudy.realtimeStationArrival/CshapStudy.realtimeStationArrival.csproj(1 hunks)CshapStudy.realtimeStationArrival/DTOs/StationDto.cs(1 hunks)CshapStudy.realtimeStationArrival/DataSources/IStationApiDataSource.cs(1 hunks)CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs(1 hunks)CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs(1 hunks)CshapStudy.realtimeStationArrival/Models/Station.cs(1 hunks)CshapStudy.realtimeStationArrival/Program.cs(1 hunks)CshapStudy.realtimeStationArrival/Repositories/IStationRepository.cs(1 hunks)CshapStudy.realtimeStationArrival/Repositories/StationError.cs(1 hunks)CshapStudy.realtimeStationArrival/Repositories/StationRepository.cs(1 hunks)CsharpStudy.2hakgi/TIL/2025_0915(1 hunks)CsharpStudy.2hakgi/TIL/2025_0916(1 hunks)CsharpStudy.DtoMapper.Tests/CsharpStudy.DtoMapper.Tests.csproj(1 hunks)CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs(1 hunks)CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs(1 hunks)CsharpStudy.DtoMapper/CsharpStudy.DtoMapper.csproj(1 hunks)CsharpStudy.DtoMapper/Mappers/PokemonMapperTest.cs(1 hunks)CsharpStudy.sln(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (19)
CshapStudy.DtoMapper/DataSource/Response.cs (1)
CshapStudy.realtimeStationArrival/Common/Response.cs (2)
Response(3-15)Response(9-14)
CshapStudy.realtimeStationArrival/DataSources/IStationApiDataSource.cs (2)
CshapStudy.realtimeStationArrival/Common/Response.cs (2)
Response(3-15)Response(9-14)CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
StationDto(7-15)
CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (2)
CshapStudy.realtimeStationArrival/Models/Station.cs (2)
Station(3-17)Station(10-16)CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
StationDto(7-15)
CshapStudy.DtoMapper/Repositories/IPokemonRepository.cs (2)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
Models(7-13)CsharpStudy.Http/Models/Pokemon.cs (1)
Pokemon(16-21)
CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs (5)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (2)
Models(7-13)PokemonMapper(5-14)CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (1)
Task(7-7)CshapStudy.DtoMapper/DataSource/PokemonApiDataSource.cs (3)
Task(18-32)PokemonApiDataSource(8-34)PokemonApiDataSource(13-16)CshapStudy.DtoMapper/DataSource/Response.cs (2)
Response(5-18)Response(11-17)CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
PokemonDto(5-66)
CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs (3)
CshapStudy.realtimeStationArrival/DataSources/IStationApiDataSource.cs (1)
Task(8-8)CshapStudy.realtimeStationArrival/Common/Response.cs (2)
Response(3-15)Response(9-14)CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
StationDto(7-15)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (2)
CsharpStudy.Http/Models/Pokemon.cs (1)
Pokemon(16-21)CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
PokemonDto(5-66)
CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (2)
CshapStudy.DtoMapper/DataSource/Response.cs (2)
Response(5-18)Response(11-17)CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
PokemonDto(5-66)
CshapStudy.realtimeStationArrival/Repositories/IStationRepository.cs (2)
CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (1)
List(10-24)CshapStudy.realtimeStationArrival/Models/Station.cs (2)
Station(3-17)Station(10-16)
CshapStudy.realtimeStationArrival/Program.cs (1)
CshapStudy.DtoMapper/Program.cs (2)
Program(3-9)Main(5-8)
CshapStudy.DtoMapper/Program.cs (1)
CshapStudy.realtimeStationArrival/Program.cs (2)
Program(3-9)Main(5-8)
CshapStudy.realtimeStationArrival/Common/Response.cs (1)
CshapStudy.DtoMapper/DataSource/Response.cs (2)
Response(5-18)Response(11-17)
CshapStudy.DtoMapper/Models/Pokemon.cs (2)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
Models(7-13)CsharpStudy.Http/Models/Pokemon.cs (1)
Pokemon(16-21)
CshapStudy.DtoMapper/Repositories/PokemonRepository.cs (5)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
Models(7-13)CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (1)
Task(7-7)CshapStudy.DtoMapper/DataSource/PokemonApiDataSource.cs (1)
Task(18-32)CshapStudy.DtoMapper/Repositories/IPokemonRepository.cs (1)
Task(7-7)CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs (1)
Task(56-71)
CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs (5)
CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
Models(7-13)CshapStudy.DtoMapper/Repositories/PokemonRepository.cs (3)
PokemonRepository(8-48)PokemonRepository(12-15)Task(17-47)CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (1)
Task(7-7)CshapStudy.DtoMapper/DataSource/Response.cs (2)
Response(5-18)Response(11-17)CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
PokemonDto(5-66)
CshapStudy.realtimeStationArrival/Repositories/StationRepository.cs (5)
CshapStudy.realtimeStationArrival/DataSources/IStationApiDataSource.cs (1)
Task(8-8)CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs (1)
Task(18-33)CshapStudy.realtimeStationArrival/Repositories/IStationRepository.cs (1)
Task(8-8)CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (1)
List(10-24)CshapStudy.realtimeStationArrival/Models/Station.cs (2)
Station(3-17)Station(10-16)
CshapStudy.DtoMapper/DataSource/PokemonApiDataSource.cs (5)
CshapStudy.DtoMapper/DataSource/IPokemonApiDataSource.cs (1)
Task(7-7)CshapStudy.DtoMapper/Repositories/PokemonRepository.cs (1)
Task(17-47)CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs (1)
Task(56-71)CshapStudy.DtoMapper/DataSource/Response.cs (2)
Response(5-18)Response(11-17)CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
PokemonDto(5-66)
CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (1)
List(10-24)
CsharpStudy.DtoMapper/Mappers/PokemonMapperTest.cs (2)
CsharpStudy.DtoMapper.Tests/Mappers/PokemonMapperTest.cs (3)
TestFixture(14-46)Test(18-28)Test(29-43)CshapStudy.DtoMapper/Mappers/PokemonMapper.cs (1)
PokemonMapper(5-14)
🔇 Additional comments (9)
CshapStudy.realtimeStationArrival/Program.cs (1)
7-7: 확인 완료 — ImplicitUsings 및 Nullable 활성화됨CshapStudy.realtimeStationArrival.csproj에 enable 및 enable가 설정되어 있어 추가 조치 불필요.
CshapStudy.DtoMapper/Program.cs (1)
7-7: ImplicitUsings가 활성화되어 있어 Console 인식 문제 없음CshapStudy.DtoMapper.csproj에 enable 및 enable로 설정되어 있어 추가 조치 불필요합니다.
CshapStudy.realtimeStationArrival/Repositories/StationError.cs (1)
3-8: InvalidInput 사용처 및 HTTP 상태 코드 매핑 명확화 필요사용처: CshapStudy.realtimeStationArrival/Repositories/StationRepository.cs:21 — StationError.InvalidInput을 반환하고 있음. 이 값이 구체적으로 어떤 입력 오류(예: HTTP 400 Bad Request / 파라미터 검증 실패)를 의미하는지 주석이나 TODO로 범위를 명시하거나, 의미가 모호하면 이름을 변경하거나 사용하지 않는다면 enum에서 제거하세요.
CshapStudy.DtoMapper/DTOs/PokemonDto.cs (1)
5-66: 전반적 매핑 품질 양호필드 커버리지와
Newtonsoft.Json어노테이션 매핑이 일관적이며, nullable 처리도 적절합니다.CsharpStudy.DtoMapper/CsharpStudy.DtoMapper.csproj (1)
9-13: 검토 코멘트 수정 — 이 프로젝트에 테스트가 존재하므로 패키지 일괄 제거 권고는 부적절합니다CsharpStudy.DtoMapper/Mappers/PokemonMapperTest.cs에서 [TestFixture], [Test] 특성 확인. 따라서 Microsoft.NET.Test.Sdk 및 NUnit(2.x) 제거 권고는 잘못되었습니다.
- 옵션 A — 이 프로젝트에 테스트를 유지하려면: NUnit을 4.x로 업그레이드해 다른 테스트 프로젝트와 버전 일치시키고 Microsoft.NET.Test.Sdk는 유지(필요 시 버전 조정).
- 옵션 B — 테스트를 별도 프로젝트로 분리하려면: PokemonMapperTest.cs를 CsharpStudy.DtoMapper.Tests로 이동한 뒤 이 프로젝트에서 Microsoft.NET.Test.Sdk 및 NUnit 패키지 제거.
Likely an incorrect or invalid review comment.
CsharpStudy.DtoMapper.Tests/CsharpStudy.DtoMapper.Tests.csproj (1)
11-15: 호환성 확인 완료 — 문제 없음 (NUnit3TestAdapter 5.1.0 + NUnit 4.4.0)
NUnit 문서상 NUnit 4는 NUnit3TestAdapter ≥ 4.5.0을 요구하며, 5.1.0은 .NET 8 및 Microsoft.NET.Test.Sdk 17.14.x와 호환됩니다. 변경 불필요.CsharpStudy.DtoMapper/Mappers/PokemonMapperTest.cs (1)
7-17: 검증 결과: PokemonMapperTest.cs가 어떤 .csproj에도 포함되어 있지 않습니다파일 CsharpStudy.DtoMapper/Mappers/PokemonMapperTest.cs는 리포지토리에 존재하지만 제공한 스크립트 결과로는 어떤 .csproj에도 포함되어 있지 않습니다 — 테스트 의도라면 파일을 CsharpStudy.DtoMapper.Tests로 이동하거나 해당 테스트 .csproj에 포함시키고, 불필요하면 삭제하세요.
Likely an incorrect or invalid review comment.
CshapStudy.realtimeStationArrival/Common/Response.cs (1)
3-15: Response 중복/불일치 정리 필요 — 리포지토리 검색 실패(“No files were searched”)rg 실행 결과로 중복 검사에 실패했습니다. CshapStudy.realtimeStationArrival/Common/Response.cs의 Response와 (DtoMapper 쪽) 다른 Response 정의의 타입/프로퍼티 불일치 여부를 확인하세요. 해결안: (1) 공용 모듈로 이동 또는 (2) 이름을 HttpResponse로 변경하고 StatusCode/Headers/Body 등 프로퍼티 타입을 통일. 레포지토리 루트에서 재검증 명령: rg -nP 'class\s+Response<' -S -C2
CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs (1)
69-71: 검증 결과 — DtoMapper의 Response.Headers는 현재 object입니다 (테스트 변경 불필요)CshapStudy.DtoMapper/DataSource/Response.cs에서 Headers가 object로 선언되어 있어 현재 테스트의
new { }사용은 유효합니다.
만약 해당 Response를IReadOnlyDictionary<string,string>로 변경하면 테스트를 아래처럼 바꿔야 합니다.- return new Response<PokemonDto>(200, new { }, new PokemonDto { Name = "ditt" }); + return new Response<PokemonDto>(200, new Dictionary<string,string>(), new PokemonDto { Name = "ditt" });Likely an incorrect or invalid review comment.
| public int StatusCode { get; set; } | ||
| public object Headers { get; set; } | ||
| public T Body { get; set; } | ||
|
|
||
| public Response(int statusCode, object headers, T body) | ||
| { | ||
| StatusCode = statusCode; | ||
| Headers = headers; | ||
| Body = body; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response.Headers를 강타입으로 통일하고, 중복 타입을 제거하세요.
Headers가 object로 선언되어 있어 컴파일 타임 안전성이 없고, realtimeStationArrival.Common.Response와 불일치합니다. 공용 Response를 한 군데로 모으거나, 동일 시그니처(IReadOnlyDictionary<string,string>)로 통일해 주세요.
적용 예시:
public class Response<T>
{
public int StatusCode { get; set; }
- public object Headers { get; set; }
+ public IReadOnlyDictionary<string, string> Headers { get; set; }
public T Body { get; set; }
- public Response(int statusCode, object headers, T body)
+ public Response(int statusCode, IReadOnlyDictionary<string, string> headers, T body)
{
StatusCode = statusCode;
Headers = headers;
Body = body;
}
}🤖 Prompt for AI Agents
In CshapStudy.DtoMapper/DataSource/Response.cs around lines 7 to 15, the Headers
property and constructor parameter are currently object which lacks compile-time
safety and differs from realtimeStationArrival.Common.Response<T>; change the
Headers property type and constructor parameter to IReadOnlyDictionary<string,
string> (or the exact common Response<T> signature if available), update
assignments accordingly, and consolidate/remove duplicate Response<T>
definitions so both use the same strongly-typed
IReadOnlyDictionary<string,string> signature.
| public enum PoKemonError | ||
| { | ||
| NetWorkError, | ||
| NotFound, | ||
| InvalidInput, | ||
| UnknownError | ||
|
|
||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
🧩 Analysis chain
공개 API 네이밍 교정(PoKemon → Pokemon, NetWork → Network)
철자/대소문자 불일치로 혼란을 야기합니다. 이번 PR 내에서 일괄 리네임 권장.
-public enum PoKemonError
+public enum PokemonError
{
- NetWorkError,
+ NetworkError,
NotFound,
InvalidInput,
UnknownError
}리네임 이후 참조 파일 전반(Repository, Tests, Interfaces)을 함께 수정해 컴파일 확인 부탁합니다.
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "=== pwd ==="
pwd
echo
echo "=== locate candidate file(s) ==="
rg -n --hidden --no-ignore-vcs -S "PoKemonError.cs" || true
rg -n --hidden --no-ignore-vcs -S "PoKemonError" --glob '!node_modules/**' --glob '!dist/**' -C2 || true
echo
echo "=== show file from review path if present ==="
if [ -f "CshapStudy.DtoMapper/Repositories/PoKemonError.cs" ]; then
sed -n '1,240p' CshapStudy.DtoMapper/Repositories/PoKemonError.cs || true
else
echo "NOT FOUND: CshapStudy.DtoMapper/Repositories/PoKemonError.cs"
fi
echo
echo "=== search repo for misspellings and correct variants ==="
rg -n --hidden --no-ignore-vcs -S "(PoKemonError|PokemonError|PoKemon|Pokemon|NetWorkError|NetworkError)" -g '!*node_modules/*' -g '!*dist/*' -C2 || true
echo
echo "=== done ==="Length of output: 628
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "=== pwd ==="
pwd
echo
echo "=== ls -la (repo root) ==="
ls -la || true
echo
echo "=== show target file ==="
if [ -f "CshapStudy.DtoMapper/Repositories/PoKemonError.cs" ]; then
sed -n '1,240p' CshapStudy.DtoMapper/Repositories/PoKemonError.cs || true
else
echo "NOT FOUND: CshapStudy.DtoMapper/Repositories/PoKemonError.cs"
fi
echo
echo "=== ripgrep (unrestricted) search for variants ==="
rg -n --hidden -uu -S --ignore-case "PoKemonError|PoKemon|NetWorkError|PokemonError|NetworkError|NetWork" -C3 || true
echo
echo "=== grep fallback search ==="
grep -nR --exclude-dir={node_modules,dist,.git} -I -i -E "PoKemonError|PoKemon|NetWorkError|PokemonError|NetworkError|NetWork" || true
echo
echo "=== done ==="Length of output: 43471
공개 API 네이밍 교정: PoKemon → Pokemon, NetWork → Network (일괄 리네임 필요)
철자·대소문자 불일치로 혼란 발생 — PR에서 enum명, 멤버, 파일명 및 전역 참조를 일괄 수정하고 빌드·테스트로 확인하세요.
-public enum PoKemonError
+public enum PokemonError
{
- NetWorkError,
+ NetworkError,
NotFound,
InvalidInput,
UnknownError
}수정 대상(발견된 위치, 최소한 아래 파일들 전부 업데이트 필요):
- CshapStudy.DtoMapper/Repositories/PoKemonError.cs — enum명 및 멤버, 파일명(PoKemonError.cs → PokemonError.cs) 변경
- CshapStudy.DtoMapper/Repositories/IPokemonRepository.cs — Task<Result<Models.Pokemon, PoKemonError>> 등 시그니처 갱신
- CshapStudy.DtoMapper/Repositories/PokemonRepository.cs — Result<Pokemon, PoKemonError> 사용처 전부 갱신
- CshapStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs — 테스트 내 PoKemonError 사용 갱신
- 저장소 전체에서 "PoKemonError" 및 "NetWorkError" 전역 검색 후 모두 치환
리네임 후 빌드 및 유닛테스트 실행으로 컴파일/레퍼런스 문제 없음 확인 필요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public enum PoKemonError | |
| { | |
| NetWorkError, | |
| NotFound, | |
| InvalidInput, | |
| UnknownError | |
| } | |
| public enum PokemonError | |
| { | |
| NetworkError, | |
| NotFound, | |
| InvalidInput, | |
| UnknownError | |
| } |
🤖 Prompt for AI Agents
In CshapStudy.DtoMapper/Repositories/PoKemonError.cs around lines 3 to 10, the
enum and member names are misspelled/cased incorrectly (PoKemon → Pokemon,
NetWorkError → NetworkError); rename the file to PokemonError.cs, change the
enum to PokemonError and its members to NetworkError, NotFound, InvalidInput,
UnknownError, then update every reference across the repository (at minimum:
IPokemonRepository.cs, PokemonRepository.cs,
CshapStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs) replacing
PoKemonError and NetWorkError usages with the corrected names, rebuild the
solution and run unit tests to resolve any remaining compiler or reference
errors.
| <ItemGroup> | ||
| <Reference Include="JetBrains.ReSharper.TestRunner.Merged"> | ||
| <HintPath>..\..\..\..\..\..\Applications\Rider.app\Contents\lib\ReSharperHost\TestRunner\netcoreapp3.0\JetBrains.ReSharper.TestRunner.Merged.dll</HintPath> | ||
| </Reference> | ||
| </ItemGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개발자 로컬 경로에 고정된 ReSharper TestRunner 참조 제거
CI/타 OS에서 즉시 빌드 실패합니다. 프로덕션 콘솔 앱에서 테스트 러너 DLL을 참조할 필요도 없습니다. 제거하세요.
- <ItemGroup>
- <Reference Include="JetBrains.ReSharper.TestRunner.Merged">
- <HintPath>..\..\..\..\..\..\Applications\Rider.app\Contents\lib\ReSharperHost\TestRunner\netcoreapp3.0\JetBrains.ReSharper.TestRunner.Merged.dll</HintPath>
- </Reference>
- </ItemGroup>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <ItemGroup> | |
| <Reference Include="JetBrains.ReSharper.TestRunner.Merged"> | |
| <HintPath>..\..\..\..\..\..\Applications\Rider.app\Contents\lib\ReSharperHost\TestRunner\netcoreapp3.0\JetBrains.ReSharper.TestRunner.Merged.dll</HintPath> | |
| </Reference> | |
| </ItemGroup> |
🤖 Prompt for AI Agents
CshapStudy.realtimeStationArrival/CshapStudy.realtimeStationArrival.csproj lines
15-19: the project file contains a hard-coded developer-local Reference to
JetBrains.ReSharper.TestRunner.Merged with a HintPath pointing into a macOS
Rider installation, which breaks CI/other OS builds and is unnecessary for a
production console app; remove the entire <Reference
Include="JetBrains.ReSharper.TestRunner.Merged">…</Reference> block from the
project file (or move it into a separate developer-only MSBuild condition if you
really need it locally), save the csproj and verify with dotnet build to confirm
the reference is gone.
| namespace CshapStudy.realtimeStationArrival.DTOs; | ||
| using Newtonsoft.Json; | ||
| using System.Collections.Generic; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네임스페이스 뒤 using 배치로 인한 컴파일 오류 및 불필요한 참조 제거
file‑scoped namespace 선언(예: namespace X;) 이후의 using 지시문은 허용되지 않습니다. 현재 라인 4~5의 using은 컴파일 에러를 유발합니다. 또한 Newtonsoft는 이 파일에서 사용하지 않으므로 제거하세요.
아래처럼 정리하세요.
using System.Text.Json.Serialization;
+using System.Collections.Generic;
-
-namespace CshapStudy.realtimeStationArrival.DTOs;
-using Newtonsoft.Json;
-using System.Collections.Generic;
+namespace CshapStudy.realtimeStationArrival.DTOs;🤖 Prompt for AI Agents
CshapStudy.realtimeStationArrival/DTOs/StationDto.cs around lines 3-6: the file
uses a file-scoped namespace declaration so any using directives must appear
before the `namespace ...;` line; move the required `using` statements above the
file-scoped `namespace` declaration and remove the unused `using
Newtonsoft.Json;` (and any other unused usings such as
System.Collections.Generic if not referenced in this DTO) so the file compiles
and contains only necessary references.
| result = await repository.GetPokemonByNameAsync("timeout"); | ||
| var errorResult = result as Result<Pokemon, PoKemonError>.Error; | ||
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); | ||
|
|
||
| await repository.GetPokemonByNameAsync("serialization-error"); | ||
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
두 번째 실패 케이스에서 이전 에러 객체를 재사용하고 있습니다.
serialization-error 호출 결과로 errorResult를 갱신해야 합니다. 현재 테스트는 잘못된 검증으로 통과/실패가 왜곡될 수 있습니다.
- await repository.GetPokemonByNameAsync("serialization-error");
- Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True);
+ result = await repository.GetPokemonByNameAsync("serialization-error");
+ errorResult = result as Result<Pokemon, PoKemonError>.Error;
+ Assert.That(errorResult!.error, Is.EqualTo(PoKemonError.UnknownError));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| result = await repository.GetPokemonByNameAsync("timeout"); | |
| var errorResult = result as Result<Pokemon, PoKemonError>.Error; | |
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); | |
| await repository.GetPokemonByNameAsync("serialization-error"); | |
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); | |
| result = await repository.GetPokemonByNameAsync("timeout"); | |
| var errorResult = result as Result<Pokemon, PoKemonError>.Error; | |
| Assert.That(errorResult!.error == PoKemonError.UnknownError, Is.True); | |
| result = await repository.GetPokemonByNameAsync("serialization-error"); | |
| errorResult = result as Result<Pokemon, PoKemonError>.Error; | |
| Assert.That(errorResult!.error, Is.EqualTo(PoKemonError.UnknownError)); |
🤖 Prompt for AI Agents
In CsharpStudy.DtoMapper.Tests/Repositories/PokemonRepositoryTest.cs around
lines 39 to 45, the test reuses the previous errorResult for the second failure
case instead of capturing the new call's result; update the second invocation to
await repository.GetPokemonByNameAsync("serialization-error") and assign its
cast to a fresh (or re-used) Result<Pokemon, PoKemonError>.Error variable, then
assert that this new errorResult.error == PoKemonError.UnknownError so the test
validates the second failure independently.
Pull request summary
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (6)
CshapStudy.realtimeStationArrival/Program.cs (5)
12-14: HttpClient 수명 관리 개선(소켓 고갈 예방 및 자원 해제)한 번만 사용할
HttpClient는 재사용 또는using으로 즉시 해제하는 편이 안전합니다.- IStationApiDataSource dataSource = new StationApiDataSource(new HttpClient()); - IStationRepository repository = new StationRepository(dataSource); + using var httpClient = new HttpClient(); + IStationApiDataSource dataSource = new StationApiDataSource(httpClient); + IStationRepository repository = new StationRepository(dataSource);
15-15: 하드코딩된 역 이름 대신 인자/입력 사용 권장실행 인자로 역명을 받되, 없으면 기본값을 쓰도록 하면 재사용성이 좋아집니다.
- var stationName = "온수"; + var stationName = (args?.Length ?? 0) > 0 ? string.Join(" ", args) : "온수";
26-29: 빈 결과 메시지 문구 다듬기(오류 아님)빈 리스트는 오류가 아니라 “조회 결과 없음”에 가깝습니다.
- Console.WriteLine("정보를 찾을 수 없거나 오류가 발생했습니다."); + Console.WriteLine("조회 결과가 없습니다.");
12-14: API 통신은 HTTPS 사용 고려
StationApiDataSource의 BaseUrl이http://로 보입니다. 가능하면https://로 전환하세요(서버 지원 시).
1-4: Program.cs: 암묵적 using 의존 제거를 위해 명시적 using 추가CshapStudy.realtimeStationArrival.csproj에 enable가 설정되어 있어 HttpClient/Any() 등 암묵적 using에 의존합니다. Program.cs 상단에 아래 using들을 명시적으로 추가하세요. Result 레코드의 Success/Error 속성명은 각각 'data'/'error'로 확인됨.
+using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; using CshapStudy.realtimeStationArrival.Common; using CshapStudy.realtimeStationArrival.DataSources; using CshapStudy.realtimeStationArrival.Models; using CshapStudy.realtimeStationArrival.Repositories;CshapStudy.realtimeStationArrival/Models/Station.cs (1)
7-11: 용어 정합성(의미 명확화) 제안
TrainLineName은 실제로 방면/행선(TrainLineNm)에 더 가깝습니다.Direction/BoundFor등으로의 리네이밍을 고려해 주세요.필드 샘플 몇 건을 출력해 의미를 확인해 보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs(1 hunks)CshapStudy.realtimeStationArrival/Get.http(1 hunks)CshapStudy.realtimeStationArrival/Models/Station.cs(1 hunks)CshapStudy.realtimeStationArrival/Program.cs(1 hunks)CshapStudy.realtimeStationArrival/Repositories/StationError.cs(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- CshapStudy.realtimeStationArrival/Get.http
🚧 Files skipped from review as they are similar to previous changes (2)
- CshapStudy.realtimeStationArrival/Repositories/StationError.cs
- CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs
🧰 Additional context used
🧬 Code graph analysis (2)
CshapStudy.realtimeStationArrival/Models/Station.cs (1)
CshapStudy.realtimeStationArrival/DTOs/StationDto.cs (1)
StationDto(7-15)
CshapStudy.realtimeStationArrival/Program.cs (5)
CshapStudy.realtimeStationArrival/DataSources/StationApiDataSource.cs (3)
Task(18-33)StationApiDataSource(8-34)StationApiDataSource(13-16)CshapStudy.realtimeStationArrival/Repositories/IStationRepository.cs (1)
Task(8-8)CshapStudy.realtimeStationArrival/Repositories/StationRepository.cs (3)
Task(17-45)StationRepository(8-46)StationRepository(12-15)CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs (1)
List(10-24)CshapStudy.realtimeStationArrival/Models/Station.cs (2)
Station(5-23)Station(12-19)
| public class Station : StationDto | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
도메인 모델이 DTO를 상속 — 계층 혼동(치명적 설계 문제)
Station은 응답 루트 DTO(StationDto: 에러메시지/리스트 보유)를 상속하면 안 됩니다. 도메인 모델과 전송 모델을 분리하세요. 또한 DTO 명칭(ArvlMsg2, TrainLineNm)을 도메인에 그대로 노출하지 않는 것이 좋습니다.
간결한 도메인 레코드 형태 제안:
-using CshapStudy.realtimeStationArrival.DTOs;
-
-namespace CshapStudy.realtimeStationArrival.Models;
-
-public class Station : StationDto
-{
- public string TrainLineName { get; }
- public string DestinationStation { get; }
- public string CurrentLocationMessage { get; }
- public string SubwayLineId { get; }
-
- public Station(string trainLineName, string destinationStation, string currentLocationMessage, string subwayLineId)
- {
- TrainLineName = trainLineName;
- DestinationStation = destinationStation;
- CurrentLocationMessage = currentLocationMessage;
- SubwayLineId = subwayLineId;
-
- }
- public string SubwayId { get; set; }
- public string TrainLineNm { get; set; }
- public string ArvlMsg2 { get; set; }
-}
+namespace CshapStudy.realtimeStationArrival.Models;
+
+public sealed record Station(
+ string TrainLineName, // 예: 방면/행선 정보(TrainLineNm)
+ string DestinationStation, // 예: BstatnNm
+ string CurrentLocationMessage, // 예: ArvlMsg3
+ string SubwayLineId, // 예: SubwayId (필요 시 호선명으로 변환)
+ string ArrivalMessage // 예: ArvlMsg2 (짧은 도착 안내)
+);매퍼도 함께 수정해야 합니다(Program.cs 코멘트의 diff 참고).
🤖 Prompt for AI Agents
In CshapStudy.realtimeStationArrival/Models/Station.cs around lines 5-6, the
Station domain model currently inherits from StationDto which mixes
transport-layer concerns into the domain and must be separated: remove the
inheritance so Station is an independent domain type (preferably a concise
immutable record with domain-appropriate property names, not DTO names like
ArvlMsg2 or TrainLineNm), create a separate StationDto for API/transport shape,
and update the mapping code (Program.cs mapper changes referenced in the review)
to map between StationDto and Station explicitly; ensure all usages are updated
to use the domain model where domain logic is needed and DTOs only for
serialization/deserialization.
| public string SubwayId { get; set; } | ||
| public string TrainLineNm { get; set; } | ||
| public string ArvlMsg2 { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DTO스러운 가변 프로퍼티 제거 필요
SubwayId/TrainLineNm/ArvlMsg2 가변 프로퍼티는 DTO 누수이며 도메인 불변식에 반합니다. 위 레코드화로 자연스럽게 제거됩니다.
🤖 Prompt for AI Agents
CshapStudy.realtimeStationArrival/Models/Station.cs around lines 20-22: Remove
the mutable DTO-like properties SubwayId, TrainLineNm, and ArvlMsg2 from the
domain Station model and instead expose them as constructor-initialized,
immutable values (e.g., convert Station to a record or provide get-only
properties set via constructor) or move these fields to a separate DTO class
used only for transport; ensure any callers are updated to construct the Station
with required immutable data or to map DTOs to the domain model before use.
| foreach (var arrival in arrivals) | ||
| { | ||
| Console.WriteLine($"[호선: {arrival.CurrentLocationMessage}] [방면: {arrival.TrainLineName}] -> {arrival.ArvlMsg2}"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
출력 필드 매핑 오류 + 누락 데이터(ArvlMsg2)로 빈 값 출력
- "호선" 라벨에
CurrentLocationMessage(= ArvlMsg3)를 사용하고 있어 의미가 뒤바뀌었습니다. "호선"은SubwayLineId(혹은 변환된 호선명)를 써야 합니다. ArvlMsg2는StationMapper에서Station으로 매핑되지 않아 현재 항상null/빈 값이 출력됩니다.
적용 제안(프로그램 출력 수정):
- Console.WriteLine($"[호선: {arrival.CurrentLocationMessage}] [방면: {arrival.TrainLineName}] -> {arrival.ArvlMsg2}");
+ Console.WriteLine($"[호선: {arrival.SubwayLineId}] [방면: {arrival.TrainLineName}] -> {arrival.ArrivalMessage}");추가로, 다음 변경을 함께 적용해 주세요(다른 파일 수정):
- Station 도메인에
ArrivalMessage속성 추가(또는 생성자 매개변수로 포함) - StationMapper에서
arrival.ArvlMsg2를ArrivalMessage로 매핑
--- a/CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs
+++ b/CshapStudy.realtimeStationArrival/Mappers/StationMapper.cs
@@
- return dto.RealtimeArrivalList.Select(arrival => new Station(
- trainLineName: arrival.TrainLineNm ?? "정보 없음",
- destinationStation: arrival.BstatnNm ?? "정보 없음",
- currentLocationMessage: arrival.ArvlMsg3 ?? "정보 없음",
- subwayLineId: arrival.SubwayId ?? "정보 없음"
- )).ToList();
+ return dto.RealtimeArrivalList.Select(arrival => new Station(
+ trainLineName: arrival.TrainLineNm ?? "정보 없음",
+ destinationStation: arrival.BstatnNm ?? "정보 없음",
+ currentLocationMessage: arrival.ArvlMsg3 ?? "정보 없음",
+ subwayLineId: arrival.SubwayId ?? "정보 없음",
+ arrivalMessage: arrival.ArvlMsg2 ?? "정보 없음"
+ )).ToList();Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In CshapStudy.realtimeStationArrival/Program.cs around lines 34 to 37, the
console output uses arrival.CurrentLocationMessage for the "호선" label (wrong
field) and prints arrival.ArvlMsg2 which is currently null because it isn't
mapped; change the output to show the station's SubwayLineId (or its converted
display name) for "호선" and use a mapped ArrivalMessage property for the arrival
text. To fix, add an ArrivalMessage property (or constructor parameter) to the
Station domain, update StationMapper to map arrival.ArvlMsg2 into
ArrivalMessage, and then update the Console.WriteLine to reference the station's
SubwayLineId/display name and the new ArrivalMessage instead of
CurrentLocationMessage and raw ArvlMsg2.
250916_11_유아리
📝 과제 정보
결과
📋 체크리스트
🔍 구현 방법
📷 실행 결과
🚨 어려웠던 점
하루종일해도 테스터코드는 못함
💡 배운 점
결과는 성공과 실패
전체적인 흐름
❓ 질문 사항
📚 참고 자료
🔄 자체 평가 & 회고