2024. 7. 6. 10:31ใDevelopment๐ฉ๐ป๐ฆณ/C#
( ์ฒซ๋ฒ์งธ ํ๋ก์ ํธ์์ API ๊ตฌํ๋ฐ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ฐ๋๊น์ง ํด๋ดค์ผ๋ฉฐ ๋ค์ ํ๋ก์ ํธ์ ๊ฐ์ด๋๋ฅผ ์ข ๋ ๊ฒฌ๊ณ ํ๊ฒ ๋ง๋ค๊ธฐ ์ํด ์ถ๊ฐ์ ์ผ๋ก ์ ๋ฆฌํด ๋จ์ต๋๋ค )
10. ์๋น์ค ๋ฐ ์ปจํธ๋กค๋ฌ ๊ตฌํ: ์ค๋ฅ ํด๊ฒฐ
์๋ก : ์ง๋ ํฌ์คํ ์์ **WorkInstructionService**์ **WorkInstructionController**๋ฅผ ํตํด ์์ ์ง์์์ CRUD ๊ธฐ๋ฅ์ ๊ตฌํํ์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ด ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ์ค๋ฅ์ ๊ทธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ตฌ์ฒด์ ์ผ๋ก ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ฅ๋ฅผ ์ ์ํ๊ฒ ํด๊ฒฐํ๊ณ , ์์คํ ์ ์์ ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.
์ฃผ์ ์ค๋ฅ ๋ฐ ํด๊ฒฐ ๋ฐฉ๋ฒ
1. CS1061 ์ค๋ฅ: ํด๋์ค์ ์ ์๋์ง ์์ ๋ฉ์๋ ํธ์ถ
์ค๋ฅ ์ค๋ช :CS1061 ์ค๋ฅ๋ ํด๋์ค์ ํธ์ถ๋ ๋ฉ์๋๊ฐ ์ ์๋์ด ์์ง ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, WorkInstructionService ํด๋์ค์์ DeleteWorkInstruction ๋ฉ์๋๊ฐ ์ ์๋์ง ์์๊ฑฐ๋ AppDbContext ํด๋์ค์ WorkInstructions ์์ฑ์ด ์์ ๋ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ:
- ํด๋์ค ์ ์ ๋ฐ ๋ฉ์๋ ํ์ธ
- WorkInstructionService ํด๋์ค์ ํ์ํ ๋ฉ์๋(DeleteWorkInstruction, GetWorkInstructions, AddWorkInstruction ๋ฑ)๊ฐ ์ ์๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
- AppDbContext ํด๋์ค์ WorkInstructions DbSet์ด ์ ์๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
์ฝ๋ ์์:
csharp์ฝ๋ ๋ณต์ฌ
public class WorkInstructionService
{
private readonly AppDbContext _context;
public WorkInstructionService(AppDbContext context)
{
_context = context;
}
public void DeleteWorkInstruction(int id)
{
var instruction = _context.WorkInstructions.Find(id);
if (instruction != null)
{
_context.WorkInstructions.Remove(instruction);
_context.SaveChanges();
}
}
// ๋ค๋ฅธ ๋ฉ์๋๋ ์ ์ฌํ๊ฒ ์ ์ํฉ๋๋ค.
}
- AppDbContext์ WorkInstructions ์ถ๊ฐ
csharp์ฝ๋ ๋ณต์ฌ
public class AppDbContext : DbContext
{
public DbSet<WorkInstruction> WorkInstructions { get; set; }
// ๋ค๋ฅธ DbSet๊ณผ ์ค์
}
2. CS7036 ์ค๋ฅ: ์์ฑ์ ๋งค๊ฐ๋ณ์ ๋ถ์กฑ
์ค๋ฅ ์ค๋ช :CS7036 ์ค๋ฅ๋ ํด๋์ค์ ์์ฑ์๊ฐ ํ์ํ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๊ณต๋ฐ์ง ๋ชปํ ๋ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, **WorkInstructionService**์ ์์ฑ์๊ฐ AppDbContext ํ์ ์ ๋งค๊ฐ๋ณ์๋ฅผ ํ์๋ก ํ์ง๋ง ์ด๋ฅผ ์ ๊ณตํ์ง ์์์ ๋ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ:
- ์์ฑ์ ๋งค๊ฐ๋ณ์ ํ์ธ
- **WorkInstructionService**๋ฅผ ์ธ์คํด์คํํ ๋ AppDbContext ์ธ์คํด์ค๋ฅผ ์ ๋ฌํ๋์ง ํ์ธํฉ๋๋ค.
์ฝ๋ ์์:
csharp์ฝ๋ ๋ณต์ฌ
public class WorkInstructionServiceCtrl : Controller
{
private readonly WorkInstructionService _workInstructionService;
public WorkInstructionServiceCtrl(AppDbContext context)
{
_workInstructionService = new WorkInstructionService(context);
}
// _workInstructionService๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
}
3. 500 ๋ด๋ถ ์๋ฒ ์ค๋ฅ
์ค๋ฅ ์ค๋ช : 500 ๋ด๋ถ ์๋ฒ ์ค๋ฅ๋ ์ฃผ๋ก ์๋ฒ์์ ๋ฐ์ํ๋ ์์ธ๋ก ์ธํด ์๋ต์ด ์คํจํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋ฌธ์์ด, ์๋น์ค ํด๋์ค์ ๊ตฌํ, ์์กด์ฑ ์ฃผ์ (DI) ์ค์ ๋ฑ์ ํ์ธํด์ผ ํฉ๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ:
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋ฌธ์์ด ํ์ธ
json์ฝ๋ ๋ณต์ฌ
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=plc_data_model1;User=root;Password=Alejd1785!;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
- ์๋น์ค ํด๋์ค์ ๊ตฌํ ํ์ธ
csharp์ฝ๋ ๋ณต์ฌ
public class WorkInstructionService
{
private readonly AppDbContext _context;
private readonly ILogger<WorkInstructionService> _logger;
public WorkInstructionService(AppDbContext context, ILogger<WorkInstructionService> logger)
{
_context = context;
_logger = logger;
}
// CRUD ๋ฉ์๋ ๊ตฌํ
}
- ์์กด์ฑ ์ฃผ์ (DI) ์ค์ ํ์ธ
csharp์ฝ๋ ๋ณต์ฌ
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureServices((context, services) =>
{
services.AddDbContext<AppDbContext>(options =>
options.UseMySql(
context.Configuration.GetConnectionString("DefaultConnection"),
ServerVersion.AutoDetect(context.Configuration.GetConnectionString("DefaultConnection"))
));
services.AddScoped<WorkInstructionService>();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSyncfusionBlazor();
});
webBuilder.Configure((context, app) =>
{
var env = context.HostingEnvironment;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapFallbackToPage("/_Host");
});
});
});
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ **WorkInstructionService**์ **WorkInstructionController**๋ฅผ ๊ตฌํํ๋ฉด์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ์ค๋ฅ์ ๊ทธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ฅ๋ฅผ ์ ์ํ๊ฒ ํด๊ฒฐํ๊ณ ์์คํ ์ ์์ ์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ์ ๋๋ฒ๊น ๋ฐฉ๋ฒ์ ํตํด ์ฝ๋๋ฅผ ๋์ฑ ๊ฒฌ๊ณ ํ๊ฒ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค.
11. ๋ก๊น ๊ณผ ๋๋ฒ๊น : ์ค์๊ฐ ๋ฌธ์ ํด๊ฒฐ
์๋ก : ์ด์ ํฌ์คํ ์์๋ **WorkInstructionService**์ **WorkInstructionController**๋ฅผ ๊ตฌํํ๋ฉด์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ์ค๋ฅ์ ๊ทธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ค์๊ฐ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค. ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ์ค๋ฅ๋ฅผ ํ์ ํ๊ณ ํด๊ฒฐํ๋ ๋ฐ ์์ด ํ์์ ์ธ ๋๊ตฌ์ ๋๋ค.
๋ก๊น ์ค์ ๋ฐ ํ์ฉ
๋ก๊น ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ๊ธฐ๋กํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ์์ธ์ ํ์ ํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. .NET Core์์๋ ILogger ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊น ์ ๊ตฌํํ ์ ์์ต๋๋ค.
1. ๋ก๊น ์ค์
Program.cs ํ์ผ์์ ๋ก๊น ์๋น์ค๋ฅผ ์ค์ ํฉ๋๋ค.
csharp์ฝ๋ ๋ณต์ฌ
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureServices((context, services) =>
{
services.AddDbContext<AppDbContext>(options =>
options.UseMySql(
context.Configuration.GetConnectionString("DefaultConnection"),
ServerVersion.AutoDetect(context.Configuration.GetConnectionString("DefaultConnection"))
));
services.AddScoped<WorkInstructionService>();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSyncfusionBlazor();
services.AddLogging(); // ๋ก๊น
์๋น์ค ์ถ๊ฐ
});
webBuilder.Configure((context, app) =>
{
var env = context.HostingEnvironment;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapFallbackToPage("/_Host");
});
});
});
2. ๋ก๊น ํ์ฉ
WorkInstructionService ํด๋์ค์์ **ILogger**๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
csharp์ฝ๋ ๋ณต์ฌ
using System.Collections.Generic;
using System.Threading.Tasks;
using WindowsFormsApp1Core.SQLModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace WindowsFormsApp1Core.WorkManagementSystem.WMSrvs
{
public class WorkInstructionService
{
private readonly AppDbContext _context;
private readonly ILogger<WorkInstructionService> _logger;
public WorkInstructionService(AppDbContext context, ILogger<WorkInstructionService> logger)
{
_context = context;
_logger = logger;
}
public async Task<IEnumerable<WorkInstruction>> GetWorkInstructionsAsync()
{
_logger.LogInformation("Fetching all work instructions.");
try
{
return await _context.WorkInstructions.ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching work instructions");
throw;
}
}
public async Task AddWorkInstructionAsync(WorkInstruction workInstruction)
{
_logger.LogInformation("Adding new work instruction: {TaskName}", workInstruction.TaskName);
try
{
_context.WorkInstructions.Add(workInstruction);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error adding work instruction");
throw;
}
}
public async Task UpdateWorkInstructionAsync(WorkInstruction workInstruction)
{
_logger.LogInformation("Updating work instruction: {TaskName}", workInstruction.TaskName);
try
{
var existing = await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == workInstruction.TaskName);
if (existing != null)
{
existing.Content = workInstruction.Content;
existing.Date = workInstruction.Date;
existing.Writer = workInstruction.Writer;
existing.Priority = workInstruction.Priority;
existing.IsCompleted = workInstruction.IsCompleted;
await _context.SaveChangesAsync();
}
else
{
_logger.LogWarning("Work instruction not found: {TaskName}", workInstruction.TaskName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating work instruction");
throw;
}
}
public async Task DeleteWorkInstructionAsync(string taskName)
{
_logger.LogInformation("Deleting work instruction: {TaskName}", taskName);
try
{
var workInstruction = await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == taskName);
if (workInstruction != null)
{
_context.WorkInstructions.Remove(workInstruction);
await _context.SaveChangesAsync();
}
else
{
_logger.LogWarning("Work instruction not found: {TaskName}", taskName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting work instruction");
throw;
}
}
public async Task<WorkInstruction> GetWorkInstructionByTaskNameAsync(string taskName)
{
_logger.LogInformation("Fetching work instruction by task name: {TaskName}", taskName);
try
{
return await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == taskName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching work instruction by task name");
throw;
}
}
}
}
๋๋ฒ๊น ์ค์ ๋ฐ ํ์ฉ
๋๋ฒ๊น ์ ์ฝ๋ ์คํ์ ์ค๋จํ๊ณ ๋จ๊ณ๋ณ๋ก ์คํ ์ํ๋ฅผ ์ ๊ฒํ ์ ์๊ฒ ํด์ค๋๋ค. Visual Studio์ ๋๋ฒ๊ฑฐ๋ฅผ ํ์ฉํ๋ฉด ์ฝ๋์ ํ๋ฆ์ ์ดํดํ๊ณ , ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ์ง์ ์ ์ ํํ ํ์ ํ ์ ์์ต๋๋ค.
1. ๋๋ฒ๊น ์ค์
Visual Studio์์ ๋๋ฒ๊น ์ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ค๋จ์ ์ค์ : ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ์ผ๋ก ์์๋๋ ์ฝ๋ ์ค์ ์ค๋จ์ ์ ์ค์ ํฉ๋๋ค. ์ค๋จ์ ์ ์ค์ ํ๋ ค๋ฉด ์ฝ๋ ์ค ์ผ์ชฝ์ ํ์ ๋ง๋๋ฅผ ํด๋ฆญํฉ๋๋ค.
- ๋๋ฒ๊น ์์: Visual Studio์์ F5 ํค๋ฅผ ๋๋ฌ ๋๋ฒ๊น ๋ชจ๋๋ก ์คํํฉ๋๋ค. ๋๋ฒ๊น ๋ชจ๋์์๋ ์ค๋จ์ ์์ ์ฝ๋ ์คํ์ด ์ค๋จ๋๊ณ , ๋ณ์ ๊ฐ, ํธ์ถ ์คํ, ๋ก์ปฌ ๊ฐ ๋ฑ์ ํ์ธํ ์ ์์ต๋๋ค.
2. ๋ณ์ ๊ฒ์ฌ ๋ฐ ๋จ๊ณ๋ณ ์คํ
์ค๋จ์ ์ ๋๋ฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- ๋ณ์ ๊ฐ ๊ฒ์ฌ: ๋ง์ฐ์ค๋ฅผ ๋ณ์ ์์ ์ฌ๋ฆฌ๋ฉด ํ์ฌ ๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
- ๋จ๊ณ๋ณ ์คํ: F10 ํค๋ฅผ ๋๋ฌ ํ ์ค์ฉ ์ฝ๋๋ฅผ ์คํํ๊ฑฐ๋, F11 ํค๋ฅผ ๋๋ฌ ํจ์ ๋ด๋ถ๋ก ๋ค์ด๊ฐ๋๋ค.
- ํธ์ถ ์คํ ํ์ธ: ํธ์ถ ์คํ ์ฐฝ์ ํตํด ํ์ฌ ํจ์๊ฐ ์ด๋ป๊ฒ ํธ์ถ๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ค์๊ฐ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ๋ก๊น ์ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ๊ธฐ๋กํ๊ณ , ๋๋ฒ๊น ์ ํตํด ์ฝ๋ ์คํ์ ๋จ๊ณ๋ณ๋ก ์ ๊ฒํ๋ฉด ์ค๋ฅ๋ฅผ ์ ์ํ๊ฒ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ์ฌ ์ฝ๋์ ๊ฐ๋ณ ๊ธฐ๋ฅ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค.
12. ์ ๋ ํ ์คํธ ์์ฑ ๋ฐ ์คํ
์๋ก : ์ด์ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ค์๊ฐ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ์ฌ ์ฝ๋์ ๊ฐ๋ณ ๊ธฐ๋ฅ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค. ์ ๋ ํ ์คํธ๋ ์ฝ๋์ ์ ๋ขฐ์ฑ์ ๋์ด๊ณ , ๋ฆฌํฉํ ๋ง ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
์ ๋ ํ ์คํธ์ ์ค์์ฑ
์ ๋ ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ๊ธฐ๋ฅ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฒ์ฆํ๋ ํ ์คํธ์ ๋๋ค. ์ ๋ ํ ์คํธ๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ์ป์ ์ ์์ต๋๋ค:
- ์ฝ๋ ์ ๋ขฐ์ฑ ์ฆ๊ฐ: ์ฝ๋ ๋ณ๊ฒฝ ์ ๊ธฐ๋ฅ์ด ์ ๋๋ก ์๋ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ๋ฌธ์ํ: ํ ์คํธ ์ผ์ด์ค๋ ์ฝ๋์ ๋์ ๋ฐฉ์์ ๋ฌธ์ํํ๋ ์ญํ ์ ํฉ๋๋ค.
- ๋ฆฌํฉํ ๋ง ์ง์: ์ฝ๋ ๋ฆฌํฉํ ๋ง ์ ๊ธฐ๋ฅ์ด ๊นจ์ง์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
xUnit ๋ฐ Moq ์ค์น
์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ํด xUnit ๋ฐ Moq ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค.
powershell์ฝ๋ ๋ณต์ฌ
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
dotnet add package Moq
์ ๋ ํ ์คํธ ์์ฑ
์ ๋ ํ ์คํธ๋ ํ๋ก์ ํธ์ ๊ธฐ๋ฅ์ ๊ฒ์ฆํ๊ธฐ ์ํด ์์ฑํฉ๋๋ค. ์๋๋ WorkInstructionService ํด๋์ค์ ๋ํ ์ ๋ ํ ์คํธ ์์ ์ ๋๋ค.
csharp์ฝ๋ ๋ณต์ฌ
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using WindowsFormsApp1Core.SQLModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMSrvs;
using Xunit;
public class WorkInstructionServiceTests
{
private readonly Mock<AppDbContext> _mockContext;
private readonly Mock<ILogger<WorkInstructionService>> _mockLogger;
private readonly WorkInstructionService _service;
public WorkInstructionServiceTests()
{
_mockContext = new Mock<AppDbContext>();
_mockLogger = new Mock<ILogger<WorkInstructionService>>();
_service = new WorkInstructionService(_mockContext.Object, _mockLogger.Object);
}
[Fact]
public async Task GetWorkInstructionsAsync_ReturnsAllInstructions()
{
// Arrange
var data = new List<WorkInstruction>
{
new WorkInstruction { TaskName = "Task1", Content = "Content1" },
new WorkInstruction { TaskName = "Task2", Content = "Content2" }
};
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
_mockContext.Setup(c => c.WorkInstructions).Returns(mockSet.Object);
// Act
var result = await _service.GetWorkInstructionsAsync();
// Assert
Assert.Equal(2, result.Count());
Assert.Equal("Task1", result.First().TaskName);
}
[Fact]
public async Task AddWorkInstructionAsync_AddsInstruction()
{
// Arrange
var newInstruction = new WorkInstruction { TaskName = "Task3", Content = "Content3" };
var mockSet = new Mock<DbSet<WorkInstruction>>();
_mockContext.Setup(c => c.WorkInstructions).Returns(mockSet.Object);
// Act
await _service.AddWorkInstructionAsync(newInstruction);
// Assert
mockSet.Verify(m => m.Add(It.IsAny<WorkInstruction>()), Times.Once());
_mockContext.Verify(c => c.SaveChangesAsync(default), Times.Once());
}
[Fact]
public async Task DeleteWorkInstructionAsync_DeletesInstruction()
{
// Arrange
var data = new List<WorkInstruction>
{
new WorkInstruction { TaskName = "Task1", Content = "Content1" },
new WorkInstruction { TaskName = "Task2", Content = "Content2" }
};
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
_mockContext.Setup(c => c.WorkInstructions).Returns(mockSet.Object);
// Act
await _service.DeleteWorkInstructionAsync("Task1");
// Assert
mockSet.Verify(m => m.Remove(It.IsAny<WorkInstruction>()), Times.Once());
_mockContext.Verify(c => c.SaveChangesAsync(default), Times.Once());
}
}
์ ๋ ํ ์คํธ ์คํ
Visual Studio๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ ํ ์คํธ๋ฅผ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํ ์คํธ ํ์๊ธฐ ์ด๊ธฐ: Visual Studio ์๋จ ๋ฉ๋ด์์ Test -> **Test Explorer**๋ฅผ ์ ํํฉ๋๋ค.
- ํ ์คํธ ์คํ: Test Explorer ์ฐฝ์์ ๋ชจ๋ ํ ์คํธ๋ฅผ ์ ํํ๊ณ , Run All ๋ฒํผ์ ํด๋ฆญํ์ฌ ํ ์คํธ๋ฅผ ์คํํฉ๋๋ค.
๋ช ๋ น์ค์์ ํ ์คํธ๋ฅผ ์คํํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค:
powershell์ฝ๋ ๋ณต์ฌ
dotnet test
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ ๋ ํ ์คํธ๋ฅผ ํตํด ์ฝ๋์ ๊ฐ๋ณ ๊ธฐ๋ฅ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ํ์ธํ ์ ์์ผ๋ฉฐ, ์ฝ๋์ ์ ๋ขฐ์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๋ ๋ณต์กํ ์๋๋ฆฌ์ค์ ๋ํ ํตํฉ ํ ์คํธ์ ๋ชจ์ ๊ฐ์ฒด(Mock Objects)๋ฅผ ์ฌ์ฉํ ํ ์คํธ ๊ธฐ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
14. CI/CD ํ์ดํ๋ผ์ธ ์ค์ ๊ณผ ํ ์คํธ ์๋ํ
์๋ก : ์ด์ ํฌ์คํ ์์๋ ํตํฉ ํ ์คํธ์ ๋ชจ์ ๊ฐ์ฒด(Mock Objects)๋ฅผ ์ฌ์ฉํ ์ ๋ ํ ์คํธ ๊ธฐ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ CI/CD(Continuous Integration/Continuous Deployment) ํ์ดํ๋ผ์ธ์ ์ค์ ํ๊ณ ํ ์คํธ ์๋ํ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. CI/CD ํ์ดํ๋ผ์ธ์ ํตํด ์ฝ๋๋ฅผ ์๋์ผ๋ก ๋น๋, ํ ์คํธ, ๋ฐฐํฌํ์ฌ ๊ฐ๋ฐ ํจ์จ์ฑ๊ณผ ์ฝ๋ ํ์ง์ ๋์ผ ์ ์์ต๋๋ค.
CI/CD ํ์ดํ๋ผ์ธ์ ํ์์ฑ
CI/CD ํ์ดํ๋ผ์ธ์ ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์๋์ผ๋ก ํตํฉํ๊ณ ๋ฐฐํฌํ๋ ํ๋ก์ธ์ค๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด๋ ๊ฐ๋ฐ ์ฃผ๊ธฐ๋ฅผ ๋จ์ถํ๊ณ , ๋ฒ๊ทธ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๋ฉฐ, ์ ํ์ ์์ ์ฑ์ ๋์ด๋ ๋ฐ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
- ์๋ํ๋ ๋น๋: ์ฝ๋ ๋ณ๊ฒฝ ์๋ง๋ค ์๋์ผ๋ก ๋น๋ํ์ฌ ์ฝ๋์ ์ปดํ์ผ ์ฌ๋ถ๋ฅผ ํ์ธํฉ๋๋ค.
- ์๋ํ๋ ํ ์คํธ: ๋น๋ ๊ณผ์ ์์ ์๋์ผ๋ก ํ ์คํธ๋ฅผ ์คํํ์ฌ ์ฝ๋์ ๊ธฐ๋ฅ์ ๊ฒ์ฆํฉ๋๋ค.
- ์๋ํ๋ ๋ฐฐํฌ: ์ฝ๋๊ฐ ๋น๋ ๋ฐ ํ ์คํธ๋ฅผ ํต๊ณผํ๋ฉด ์๋์ผ๋ก ๋ฐฐํฌํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ๋น ๋ฅด๊ฒ ์ฌ์ฉ์์๊ฒ ์ ๋ฌํฉ๋๋ค.
GitHub Actions๋ฅผ ์ฌ์ฉํ CI/CD ํ์ดํ๋ผ์ธ ์ค์
GitHub Actions๋ GitHub์์ ์ ๊ณตํ๋ CI/CD ๋๊ตฌ๋ก, ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ฐ์ํ ๋๋ง๋ค ์๋์ผ๋ก ์ํฌํ๋ก์ฐ๋ฅผ ์คํํ ์ ์์ต๋๋ค. ๋ค์์ GitHub Actions๋ฅผ ์ฌ์ฉํ์ฌ CI/CD ํ์ดํ๋ผ์ธ์ ์ค์ ํ๋ ์์ ์ ๋๋ค.
1. GitHub Actions ์ํฌํ๋ก์ฐ ํ์ผ ์์ฑ
๋ฆฌํฌ์งํ ๋ฆฌ์ .github/workflows ๋๋ ํ ๋ฆฌ์ ci-cd-pipeline.yml ํ์ผ์ ์์ฑํฉ๋๋ค.
yaml์ฝ๋ ๋ณต์ฌ
name: CI/CD Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --no-build --verbosity normal
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
- name: Publish
run: dotnet publish --configuration Release --no-build -o ./publish
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: 'YourAppName'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ./publish
ํ ์คํธ ์๋ํ
ํ ์คํธ ์๋ํ๋ฅผ ํตํด ๋ชจ๋ ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ํตํฉ๋ ๋๋ง๋ค ์๋์ผ๋ก ํ ์คํธ๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ์ฝ๋์ ์ ๋ขฐ์ฑ์ ๋์ด๊ณ , ๋ฒ๊ทธ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
1. ํ ์คํธ ํ๋ก์ ํธ ์ค์
ํ ์คํธ ํ๋ก์ ํธ๋ฅผ ์ค์ ํ๊ณ , ํ์ํ ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค.
bash์ฝ๋ ๋ณต์ฌ
dotnet new xunit -o Tests
dotnet add Tests package Moq
dotnet add Tests package Microsoft.EntityFrameworkCore.InMemory
2. ํ ์คํธ ์ฝ๋ ์์ฑ
ํ ์คํธ ํ๋ก์ ํธ์ ์ ๋ ํ ์คํธ์ ํตํฉ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
csharp์ฝ๋ ๋ณต์ฌ
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using WindowsFormsApp1Core.SQLModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMSrvs;
using Xunit;
public class WorkInstructionServiceTests
{
private readonly Mock<AppDbContext> _mockContext;
private readonly Mock<ILogger<WorkInstructionService>> _mockLogger;
private readonly WorkInstructionService _service;
public WorkInstructionServiceTests()
{
_mockContext = new Mock<AppDbContext>();
_mockLogger = new Mock<ILogger<WorkInstructionService>>();
_service = new WorkInstructionService(_mockContext.Object, _mockLogger.Object);
}
[Fact]
public async Task GetWorkInstructionsAsync_ReturnsAllInstructions()
{
// Arrange
var data = new List<WorkInstruction>
{
new WorkInstruction { TaskName = "Task1", Content = "Content1" },
new WorkInstruction { TaskName = "Task2", Content = "Content2" }
};
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
_mockContext.Setup(c => c.WorkInstructions).Returns(mockSet.Object);
// Act
var result = await _service.GetWorkInstructionsAsync();
// Assert
Assert.Equal(2, result.Count());
Assert.Equal("Task1", result.First().TaskName);
}
}
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ CI/CD ํ์ดํ๋ผ์ธ์ ์ค์ ํ๊ณ , ํ ์คํธ ์๋ํ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. GitHub Actions๋ฅผ ์ฌ์ฉํ์ฌ CI/CD ํ์ดํ๋ผ์ธ์ ์ค์ ํ๊ณ , ์๋์ผ๋ก ๋น๋, ํ ์คํธ, ๋ฐฐํฌํ๋ ํ๋ก์ธ์ค๋ฅผ ๊ตฌ์ฑํ์ต๋๋ค. ํ ์คํธ ์๋ํ๋ฅผ ํตํด ๋ชจ๋ ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ํตํฉ๋ ๋๋ง๋ค ์๋์ผ๋ก ํ ์คํธ๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ํตํด ์ฝ๋์ ์ ๋ขฐ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ์ฝ๋ ํ์ง์ ๋์ด๋ ๋ค์ํ ๋๊ตฌ์ ๊ธฐ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค.
15. ์ฝ๋ ํ์ง ํฅ์์ ์ํ ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ ์ฌ์ฉ
์๋ก : ์ด์ ํฌ์คํ ์์๋ CI/CD ํ์ดํ๋ผ์ธ ์ค์ ๊ณผ ํ ์คํธ ์๋ํ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ฝ๋ ํ์ง์ ๋์ด๊ธฐ ์ํ ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ ์ต๋๋ค. ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ ์ฝ๋์ ์ ์ฌ์ ์ธ ๋ฒ๊ทธ, ๋ณด์ ์ทจ์ฝ์ , ์คํ์ผ ๋ฌธ์ ๋ฑ์ ์ฌ์ ์ ๋ฐ๊ฒฌํ์ฌ ์ฝ๋ ํ์ง์ ํฅ์์ํค๋ ๋ฐ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ์ ํ์์ฑ
์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ ์์ค ์ฝ๋๋ฅผ ์คํํ์ง ์๊ณ ๋ถ์ํ์ฌ ์ฝ๋์ ๊ฒฐํจ์ ์ฐพ๋ ๋๊ตฌ์ ๋๋ค. ์ด๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค:
- ๋ฒ๊ทธ ์ฌ์ ๋ฐ๊ฒฌ: ์ฝ๋์ ์ ์ฌ์ ์ธ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๋ฐ๊ฒฌํ์ฌ ์์ ํ ์ ์์ต๋๋ค.
- ์ฝ๋ ์ผ๊ด์ฑ ์ ์ง: ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ์ค์ํ์ฌ ์ผ๊ด๋ ์ฝ๋ ๋ฒ ์ด์ค๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.
- ๋ณด์ ๊ฐํ: ๋ณด์ ์ทจ์ฝ์ ์ ์ฌ์ ์ ๋ฐ๊ฒฌํ์ฌ ์์ ํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
- ์ฝ๋ ์ ์ง๋ณด์์ฑ ํฅ์: ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ฌ ์ฅ๊ธฐ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ฝ์ต๋๋ค.
SonarQube๋ฅผ ์ฌ์ฉํ ์ ์ ์ฝ๋ ๋ถ์
SonarQube๋ ์ฝ๋ ํ์ง ๊ด๋ฆฌ ๋๊ตฌ๋ก, ๋ค์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ง์ํ๋ฉฐ, ์ฝ๋์ ํ์ง, ๋ณด์, ์ ์ง๋ณด์์ฑ์ ํ๊ฐํฉ๋๋ค. SonarQube๋ฅผ ์ฌ์ฉํ์ฌ .NET ํ๋ก์ ํธ๋ฅผ ๋ถ์ํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. SonarQube ์ค์น ๋ฐ ์ค์
SonarQube๋ฅผ ์ค์นํ๊ณ ์ค์ ํ๋ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- SonarQube ๋ค์ด๋ก๋ ๋ฐ ์ค์น: SonarQube ๊ณต์ ์น์ฌ์ดํธ์์ SonarQube๋ฅผ ๋ค์ด๋ก๋ํ๊ณ ์ค์นํฉ๋๋ค.
- SonarQube ์๋ฒ ์คํ: SonarQube ์๋ฒ๋ฅผ ์คํํ์ฌ ์น ์ธํฐํ์ด์ค์ ์ ๊ทผํ ์ ์๋๋ก ์ค์ ํฉ๋๋ค.
- bash์ฝ๋ ๋ณต์ฌ # SonarQube ์๋ฒ ์คํ ./bin/linux-x86-64/sonar.sh start
- ์น ๋ธ๋ผ์ฐ์ ์์ SonarQube ์ ์: ์น ๋ธ๋ผ์ฐ์ ์์ **http://localhost:9000**์ ์ ์ํ์ฌ SonarQube ๋์๋ณด๋์ ์ ๊ทผํฉ๋๋ค.
2. SonarQube ํ๋ก์ ํธ ์ค์
- SonarQube ํ ํฐ ์์ฑ: SonarQube ๋์๋ณด๋์์ ์๋ก์ด ํ๋ก์ ํธ๋ฅผ ์์ฑํ๊ณ , ํ๋ก์ ํธ ํค์ ์ด๋ฆ์ ์ ๋ ฅํฉ๋๋ค. ํ๋ก์ ํธ์ ๋ํ ์ธ์ฆ ํ ํฐ์ ์์ฑํฉ๋๋ค.
- SonarScanner ์ค์น: SonarScanner๋ ์์ค ์ฝ๋๋ฅผ ๋ถ์ํ์ฌ SonarQube ์๋ฒ๋ก ๊ฒฐ๊ณผ๋ฅผ ์ ์กํ๋ ๋๊ตฌ์ ๋๋ค. ๋ค์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ SonarScanner๋ฅผ ์ค์นํฉ๋๋ค.
- bash์ฝ๋ ๋ณต์ฌ # SonarScanner ์ค์น dotnet tool install --global dotnet-sonarscanner
- SonarQube ์ค์ ํ์ผ ์์ฑ: ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ sonar-project.properties ํ์ผ์ ์์ฑํ๊ณ , SonarQube ์๋ฒ์ ํ๋ก์ ํธ ์ ๋ณด๋ฅผ ์ค์ ํฉ๋๋ค.
- properties์ฝ๋ ๋ณต์ฌ # ํ๋ก์ ํธ ํค์ ์ด๋ฆ ์ค์ sonar.projectKey=YourProjectKey sonar.projectName=YourProjectName # SonarQube ์๋ฒ URL ์ค์ sonar.host.url=http://localhost:9000 # ์์ค ์ฝ๋ ๋๋ ํ ๋ฆฌ ์ค์ sonar.sources=. # ์ธ์ฆ ํ ํฐ ์ค์ sonar.login=YourSonarQubeToken
3. ์ฝ๋ ๋ถ์ ๋ฐ ๊ฒฐ๊ณผ ํ์ธ
- SonarScanner๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ๋ถ์:
- bash์ฝ๋ ๋ณต์ฌ # SonarScanner๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ๋ถ์ dotnet sonarscanner begin /k:"YourProjectKey" /d:sonar.login="YourSonarQubeToken" dotnet build dotnet sonarscanner end /d:sonar.login="YourSonarQubeToken"
- SonarQube ๋์๋ณด๋์์ ๊ฒฐ๊ณผ ํ์ธ: SonarQube ๋์๋ณด๋์์ ํ๋ก์ ํธ๋ฅผ ์ ํํ๊ณ , ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํฉ๋๋ค. ์ฝ๋์ ๋ฒ๊ทธ, ๋ณด์ ์ทจ์ฝ์ , ์ฝ๋ ์ค๋ฉ ๋ฑ์ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
StyleCop์ ์ฌ์ฉํ ์ฝ๋ ์คํ์ผ ๊ฒ์ฌ
StyleCop์ .NET ์ฝ๋๋ฅผ ๋์์ผ๋ก ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ๊ฒ์ฌํ๊ณ , ์ฝ๋์ ์ผ๊ด์ฑ์ ์ ์งํ๋ ๋ฐ ๋์์ ์ฃผ๋ ๋๊ตฌ์ ๋๋ค.
1. StyleCop ์ค์น
ํ๋ก์ ํธ์ StyleCop์ ์ค์นํฉ๋๋ค.
bash์ฝ๋ ๋ณต์ฌ
# StyleCop ์ค์น
dotnet add package StyleCop.Analyzers
2. StyleCop ์ค์ ํ์ผ ์์ฑ
ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ stylecop.json ํ์ผ์ ์์ฑํ๊ณ , ์คํ์ผ ๊ท์น์ ์ค์ ํฉ๋๋ค.
json์ฝ๋ ๋ณต์ฌ
{
"settings": {
"documentationRules": {
"companyName": "YourCompanyName",
"copyrightText": "Copyright © YourCompanyName. All rights reserved."
}
}
}
3. ์ฝ๋ ์คํ์ผ ๊ฒ์ฌ
Visual Studio ๋๋ CLI๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ๋น๋ํ๋ฉด StyleCop ๊ท์น์ ๋ฐ๋ผ ์ฝ๋ ์คํ์ผ์ ๊ฒ์ฌํ๊ณ , ์๋ฐ ์ฌํญ์ ๊ฒฝ๊ณ ๋ก ํ์ํฉ๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ์ฝ๋ ํ์ง์ ๋์ด๊ธฐ ์ํ ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ์ธ SonarQube์ StyleCop์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. SonarQube๋ฅผ ํตํด ์ฝ๋์ ํ์ง, ๋ณด์, ์ ์ง๋ณด์์ฑ์ ํ๊ฐํ๊ณ , StyleCop์ ํตํด ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ์ค์ํ์ฌ ์ผ๊ด๋ ์ฝ๋ ๋ฒ ์ด์ค๋ฅผ ์ ์งํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ ์ฝ๋์ ์ ๋ขฐ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ด๊ณ , ์ฅ๊ธฐ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๋ ๋ค์ํ ์ฝ๋ ํ์ง ํฅ์ ๊ธฐ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
16. ์ ๋ ํ ์คํธ ์์ฑ ๋ฐ ์คํ
์๋ก : ์ด์ ํฌ์คํ ์์๋ ์ฝ๋ ํ์ง์ ๋์ด๊ธฐ ์ํ ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์๊ฐํ์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ ์์ฑ ๋ฐ ์คํ์ ํตํด ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ๋ขฐ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ ๋ ํ ์คํธ๋ ์ฝ๋์ ๊ฐ๋ณ ๋จ์๋ฅผ ํ ์คํธํ์ฌ ์ฝ๋์ ์ ํ์ฑ๊ณผ ๊ธฐ๋ฅ์ ๊ฒ์ฆํ๋ ์ค์ํ ๊ณผ์ ์ ๋๋ค.
์ ๋ ํ ์คํธ์ ์ค์์ฑ
์ ๋ ํ ์คํธ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ๋ค์๊ณผ ๊ฐ์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค:
- ๋ฒ๊ทธ ์กฐ๊ธฐ ๋ฐ๊ฒฌ: ์ฝ๋์ ์์ ๋จ์์์ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ์ฌ ์์ ํ ์ ์์ต๋๋ค.
- ์ฝ๋ ๋ณ๊ฒฝ์ ์์ ์ฑ: ์ฝ๋ ์์ ์ ๊ธฐ์กด ๊ธฐ๋ฅ์ด ์ ์์ ์ผ๋ก ์๋ํ๋์ง ๊ฒ์ฆํ ์ ์์ต๋๋ค.
- ๋ฌธ์ํ: ์ฝ๋์ ์์ ๋์์ ๋ช ํํ ํ์ฌ ๋ฌธ์ํ์ ์ญํ ์ ํฉ๋๋ค.
- ๋ฆฌํฉํ ๋ง ์ง์: ๋ฆฌํฉํ ๋ง ์ ์ฝ๋์ ๋์์ ๋ณด์ฅํ์ฌ ์์ ํ๊ฒ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
xUnit์ ์ฌ์ฉํ ์ ๋ ํ ์คํธ
xUnit์ .NET ์ฝ์ด์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ ๋ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. xUnit์ ์ฌ์ฉํ์ฌ .NET ํ๋ก์ ํธ์ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค.
1. xUnit ํจํค์ง ์ค์น
ํ๋ก์ ํธ์ xUnit ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค.
bash์ฝ๋ ๋ณต์ฌ
# xUnit ๋ฐ ๊ด๋ จ ํจํค์ง ์ค์น
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
dotnet add package Moq
2. ์ ๋ ํ ์คํธ ํด๋์ค ์์ฑ
์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ ํด๋์ค๋ฅผ ์์ฑํฉ๋๋ค. ์์ ๋ก WorkInstructionService ํด๋์ค์ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ฒ ์ต๋๋ค.
WorkInstructionServiceTests.cs:
csharp์ฝ๋ ๋ณต์ฌ
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using WindowsFormsApp1Core.SQLModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMSrvs;
using Xunit;
public class WorkInstructionServiceTests
{
private readonly Mock<AppDbContext> _mockContext;
private readonly Mock<ILogger<WorkInstructionService>> _mockLogger;
private readonly WorkInstructionService _service;
public WorkInstructionServiceTests()
{
_mockContext = new Mock<AppDbContext>();
_mockLogger = new Mock<ILogger<WorkInstructionService>>();
_service = new WorkInstructionService(_mockContext.Object, _mockLogger.Object);
}
[Fact]
public async Task GetWorkInstructionsAsync_ReturnsAllInstructions()
{
// Arrange
var data = new List<WorkInstruction>
{
new WorkInstruction { TaskName = "Task1", Content = "Content1" },
new WorkInstruction { TaskName = "Task2", Content = "Content2" }
}.AsQueryable();
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
_mockContext.Setup(c => c.WorkInstructions).Returns(mockSet.Object);
// Act
var result = await _service.GetWorkInstructionsAsync();
// Assert
Assert.Equal(2, result.Count());
Assert.Equal("Task1", result.First().TaskName);
}
[Fact]
public async Task AddWorkInstructionAsync_AddsInstruction()
{
// Arrange
var newInstruction = new WorkInstruction { TaskName = "Task3", Content = "Content3" };
var mockSet = new Mock<DbSet<WorkInstruction>>();
_mockContext.Setup(m => m.WorkInstructions).Returns(mockSet.Object);
// Act
await _service.AddWorkInstructionAsync(newInstruction);
// Assert
mockSet.Verify(m => m.Add(It.IsAny<WorkInstruction>()), Times.Once());
_mockContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async Task UpdateWorkInstructionAsync_UpdatesExistingInstruction()
{
// Arrange
var existingInstruction = new WorkInstruction { TaskName = "Task1", Content = "Content1" };
var updatedInstruction = new WorkInstruction { TaskName = "Task1", Content = "UpdatedContent" };
var data = new List<WorkInstruction> { existingInstruction }.AsQueryable();
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
_mockContext.Setup(m => m.WorkInstructions).Returns(mockSet.Object);
// Act
await _service.UpdateWorkInstructionAsync(updatedInstruction);
// Assert
Assert.Equal("UpdatedContent", existingInstruction.Content);
_mockContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async Task DeleteWorkInstructionAsync_DeletesExistingInstruction()
{
// Arrange
var existingInstruction = new WorkInstruction { TaskName = "Task1", Content = "Content1" };
var data = new List<WorkInstruction> { existingInstruction }.AsQueryable();
var mockSet = new Mock<DbSet<WorkInstruction>>();
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<WorkInstruction>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
_mockContext.Setup(m => m.WorkInstructions).Returns(mockSet.Object);
// Act
await _service.DeleteWorkInstructionAsync(existingInstruction.TaskName);
// Assert
mockSet.Verify(m => m.Remove(It.IsAny<WorkInstruction>()), Times.Once());
_mockContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
}
3. ํ ์คํธ ์คํ
Visual Studio์์ ํ ์คํธ๋ฅผ ์คํํ๊ฑฐ๋, CLI๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ๋ฅผ ์คํํ ์ ์์ต๋๋ค.
bash์ฝ๋ ๋ณต์ฌ
# CLI์์ ํ
์คํธ ์คํ
dotnet test
ํ ์คํธ ๊ฒฐ๊ณผ๋ ์ฑ๊ณต ์ฌ๋ถ์ ํจ๊ป ์์ธํ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ xUnit์ ์ฌ์ฉํ์ฌ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ์ ๋ ํ ์คํธ๋ฅผ ํตํด ์ฝ๋์ ์ ํ์ฑ๊ณผ ๊ธฐ๋ฅ์ ๊ฒ์ฆํ๊ณ , ์ฝ๋ ๋ณ๊ฒฝ ์ ๊ธฐ์กด ๊ธฐ๋ฅ์ ์ ์ ์๋์ ๋ณด์ฅํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๋ ๋ค์ํ ํ ์คํธ ๊ธฐ๋ฒ๊ณผ ๋๊ตฌ๋ฅผ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
17. ๋ก๊น ๋ฐ ๋๋ฒ๊น
์๋ก : ์ด์ ํฌ์คํ ์์๋ ์ ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ์ฌ ์ฝ๋์ ์์ ์ฑ์ ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๊ณ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ๋ฌธ์ ๋ฅผ ์ ์ํ๊ฒ ํ์ ํ๊ณ ์์ ํ๋ ๋ฐ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
๋ก๊น ์ ์ค์์ฑ
๋ก๊น ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ ์ค ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋กํ์ฌ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๋ ๋ฐ ์ค์ํ ๋๊ตฌ์ ๋๋ค. ๋ค์์ ๋ก๊น ์ ์ฃผ์ ์ด์ ์ ๋๋ค:
- ๋ฌธ์ ์ง๋จ: ๋ฐ์ํ ๋ฌธ์ ์ ์์ธ์ ์ ์ํ๊ฒ ํ์ ํ ์ ์์ต๋๋ค.
- ์ด๋ ฅ ๊ธฐ๋ก: ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ ์ด๋ ฅ์ ๊ธฐ๋กํ์ฌ ์ถํ ๋ถ์์ด ๊ฐ๋ฅํฉ๋๋ค.
- ์ค์๊ฐ ๋ชจ๋ํฐ๋ง: ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
- ๋ฌธ์ ์๋ฐฉ: ์ ์ฌ์ ์ธ ๋ฌธ์ ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ์ฌ ์๋ฐฉํ ์ ์์ต๋๋ค.
.NET Core์์ ๋ก๊น ์ค์
.NET Core์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ ๋ก๊น ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๊น ์ ์ค์ ํ ์ ์์ต๋๋ค.
1. ๋ก๊น ์ค์ ์ถ๊ฐ
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddDebug();
});
}
2. ๋ก๊น ์๋น์ค ๋ฑ๋ก
Startup.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddLogging();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
logger.LogInformation("Application started.");
}
}
๋ก๊น ์ฌ์ฉ ์์
๋ก๊น ์ ์ฌ์ฉํ์ฌ ์ฝ๋์ ์ฃผ์ ๋ถ๋ถ์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์๋ฅผ ๋ค์ด, WorkInstructionService ํด๋์ค์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค.
WorkInstructionService.cs:
csharp์ฝ๋ ๋ณต์ฌ
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WindowsFormsApp1Core.SQLModels;
using WindowsFormsApp1Core.WorkManagementSystem.WMModels;
namespace WindowsFormsApp1Core.WorkManagementSystem.WMSrvs
{
public class WorkInstructionService
{
private readonly AppDbContext _context;
private readonly ILogger<WorkInstructionService> _logger;
public WorkInstructionService(AppDbContext context, ILogger<WorkInstructionService> logger)
{
_context = context;
_logger = logger;
}
public async Task<IEnumerable<WorkInstruction>> GetWorkInstructionsAsync()
{
_logger.LogInformation("Fetching all work instructions.");
try
{
return await _context.WorkInstructions.ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching work instructions");
throw;
}
}
public async Task AddWorkInstructionAsync(WorkInstruction workInstruction)
{
_logger.LogInformation("Adding a new work instruction: {TaskName}", workInstruction.TaskName);
try
{
_context.WorkInstructions.Add(workInstruction);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error adding work instruction");
throw;
}
}
public async Task UpdateWorkInstructionAsync(WorkInstruction workInstruction)
{
_logger.LogInformation("Updating work instruction: {TaskName}", workInstruction.TaskName);
try
{
var existing = await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == workInstruction.TaskName);
if (existing != null)
{
existing.Content = workInstruction.Content;
existing.Date = workInstruction.Date;
existing.Writer = workInstruction.Writer;
existing.Priority = workInstruction.Priority;
existing.IsCompleted = workInstruction.IsCompleted;
await _context.SaveChangesAsync();
}
else
{
_logger.LogWarning("Work instruction not found: {TaskName}", workInstruction.TaskName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating work instruction");
throw;
}
}
public async Task DeleteWorkInstructionAsync(string taskName)
{
_logger.LogInformation("Deleting work instruction: {TaskName}", taskName);
try
{
var workInstruction = await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == taskName);
if (workInstruction != null)
{
_context.WorkInstructions.Remove(workInstruction);
await _context.SaveChangesAsync();
}
else
{
_logger.LogWarning("Work instruction not found: {TaskName}", taskName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting work instruction");
throw;
}
}
public async Task<WorkInstruction> GetWorkInstructionByTaskNameAsync(string taskName)
{
_logger.LogInformation("Fetching work instruction by task name: {TaskName}", taskName);
try
{
return await _context.WorkInstructions.FirstOrDefaultAsync(w => w.TaskName == taskName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching work instruction by task name");
throw;
}
}
}
}
๋๋ฒ๊น
๋๋ฒ๊น ์ ์ฝ๋์ ์คํ์ ๋จ๊ณ๋ณ๋ก ์ถ์ ํ์ฌ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ์์ ํ๋ ๊ณผ์ ์ ๋๋ค. Visual Studio์ ๋๋ฒ๊ฑฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋์ ํ๋ฆ์ ์ดํดํ๊ณ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
1. ์ค๋จ์ ์ค์
์ค๋จ์ (Breakpoint)์ ์ค์ ํ์ฌ ํน์ ์ง์ ์์ ์ฝ๋ ์คํ์ ์ค์งํ๊ณ ๋ณ์์ ๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
2. ๋จ๊ณ๋ณ ์คํ
๋๋ฒ๊ฑฐ์์ F10 ํค๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ๋ผ์ธ์ ํ ์ค์ฉ ์คํํ๊ณ , F11 ํค๋ฅผ ์ฌ์ฉํ์ฌ ํจ์ ๋ด๋ถ๋ก ๋ค์ด๊ฐ๋๋ค.
3. ๋ณ์ ๊ฐ ํ์ธ
๋๋ฒ๊ฑฐ ์ฐฝ์์ ๋ณ์์ ๊ฐ์ ํ์ธํ๊ณ , Watch ์ฐฝ์ ๋ณ์๋ฅผ ์ถ๊ฐํ์ฌ ๊ฐ์ ์ถ์ ํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๊ณ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ๋ก๊น ์ ํตํด ์คํ ์ค ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋กํ๊ณ , ๋๋ฒ๊น ์ ํตํด ์ฝ๋์ ํ๋ฆ์ ์ดํดํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๋ ๋ค์ํ ๋๋ฒ๊น ๊ธฐ๋ฒ๊ณผ ๋๊ตฌ๋ฅผ ์๊ฐํ๊ฒ ์ต๋๋ค.
18. ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์
์๋ก : ์ด์ ํฌ์คํ ์์๋ ๋ก๊น ๊ณผ ๋๋ฒ๊น ์ ํตํด ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๊ณ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ํตํด ์ฝ๋ ํ์ง์ ํฅ์์ํค๊ณ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๋ฐฉ์งํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ์ค์ํ ํ์ง ๊ด๋ฆฌ ๋๊ตฌ์ ๋๋ค.
์ฝ๋ ๋ฆฌ๋ทฐ์ ์ค์์ฑ
์ฝ๋ ๋ฆฌ๋ทฐ๋ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ ํ์๋ค์ด ์์ฑํ ์ฝ๋๋ฅผ ๊ฒํ ํ๋ ๊ณผ์ ์ ๋๋ค. ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ฃผ์ ๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ฝ๋ ํ์ง ํฅ์: ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํตํด ์ฝ๋์ ํ์ง์ ๋์ด๊ณ , ์ ์ฌ์ ์ธ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
- ์ง์ ๊ณต์ : ํ์ ๊ฐ์ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํตํด ์ง์์ ๊ณต์ ํ๊ณ , ์ฝ๋ ์์ฑ ์คํ์ผ์ ํต์ผํ ์ ์์ต๋๋ค.
- ์ต์ ํ: ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํตํด ์ฑ๋ฅ์ ์ต์ ํํ๊ณ , ์ฝ๋์ ๊ฐ๋ ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ๊ต์ก: ์ฝ๋ ๋ฆฌ๋ทฐ๋ ์ ์ ๊ฐ๋ฐ์๋ ๊ฒฝํ์ด ์ ์ ๊ฐ๋ฐ์์๊ฒ ์ข์ ํ์ต ๊ธฐํ๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํจ๊ณผ์ ์ธ ์ฝ๋ ๋ฆฌ๋ทฐ ๋ฐฉ๋ฒ
ํจ๊ณผ์ ์ธ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- ์์ ๋จ์๋ก ๋ฆฌ๋ทฐ: ์ฝ๋ ๋ฆฌ๋ทฐ๋ ์์ ๋จ์๋ก ์์ฃผ ์ํํ๋ ๊ฒ์ด ํจ๊ณผ์ ์ ๋๋ค. ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ์์๋ก ๋ฆฌ๋ทฐ๊ฐ ๋ ๊ฐ๋จํ๊ณ , ๋ ์์ฃผ ๋ฆฌ๋ทฐํ ์ ์์ต๋๋ค.
- ๋ช ํํ ๊ธฐ์ค ์ค์ : ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์ํ ๋ช ํํ ๊ธฐ์ค์ ์ค์ ํ์ฌ ์ผ๊ด๋ ๋ฆฌ๋ทฐ๋ฅผ ์ํํฉ๋๋ค. ์ฝ๋ ์คํ์ผ, ๋ค์ด๋ฐ ๊ท์น, ์ฃผ์ ์์ฑ ๋ฑ์ ๊ธฐ์ค์ ๋ฌธ์ํํฉ๋๋ค.
- ์๋ฏธ ์๋ ํผ๋๋ฐฑ ์ ๊ณต: ํผ๋๋ฐฑ์ ๊ตฌ์ฒด์ ์ด๊ณ ๊ฑด์ค์ ์ด์ด์ผ ํฉ๋๋ค. ๋จ์ํ "์ฝ๋๊ฐ ์ข์ง ์๋ค"๋ ํผ๋๋ฐฑ๋ณด๋ค๋ "์ด ๋ถ๋ถ์ ์ด๋ ๊ฒ ์์ ํ๋ฉด ๋ ์ข๊ฒ ๋ค"๋ ๊ตฌ์ฒด์ ์ธ ์ ์์ ํฉ๋๋ค.
- ์๋ํ ๋๊ตฌ ์ฌ์ฉ: ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์๋ํํ ์ ์๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋ณธ์ ์ธ ์ฝ๋ ์คํ์ผ๊ณผ ํ์ง ๊ฒ์ฌ๋ฅผ ์๋์ผ๋ก ์ํํฉ๋๋ค.
์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ
์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ ์ฝ๋๋ฅผ ์คํํ์ง ์๊ณ ์์ค ์ฝ๋๋ฅผ ๋ถ์ํ์ฌ ์ ์ฌ์ ์ธ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํ๋ ๋๊ตฌ์ ๋๋ค. ๋ค์์ ๋ํ์ ์ธ ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ์ ๋๋ค:
- SonarQube: ์คํ ์์ค ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ก, ์ฝ๋ ํ์ง์ ์ง์์ ์ผ๋ก ๊ฒ์ฌํ๊ณ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
- ReSharper: JetBrains์์ ์ ๊ณตํ๋ Visual Studio์ฉ ํ๋ฌ๊ทธ์ธ์ผ๋ก, ์ฝ๋ ๋ถ์, ๋ฆฌํฉํ ๋ง, ์ฝ๋ ์์ฑ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- StyleCop: C# ์ฝ๋ ์คํ์ผ ๋ฐ ํ์ง ๊ฒ์ฌ ๋๊ตฌ๋ก, ์ฝ๋ ์คํ์ผ์ ์ผ๊ด๋๊ฒ ์ ์งํ ์ ์์ต๋๋ค.
์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ ์ฌ์ฉ ์์
SonarQube ์ค์ ๋ฐ ์ฌ์ฉ:
- SonarQube ์ค์น: SonarQube๋ฅผ ์ค์นํ๊ณ ์คํํฉ๋๋ค. ์ค์น ๋ฐฉ๋ฒ์ SonarQube ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
- ํ๋ก์ ํธ ์ค์ : SonarQube ํ๋ก์ ํธ๋ฅผ ์์ฑํ๊ณ , sonar-project.properties ํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ ์์ฑํฉ๋๋ค.
- properties์ฝ๋ ๋ณต์ฌ sonar.projectKey=my_project_key sonar.projectName=My Project sonar.projectVersion=1.0 sonar.sources=.
- SonarQube ์ค์บ๋ ์คํ: SonarQube ์ค์บ๋๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ๋ฅผ ๋ถ์ํฉ๋๋ค. ๋ช ๋ น์ค์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํฉ๋๋ค.
- sh์ฝ๋ ๋ณต์ฌ sonar-scanner
ReSharper ์ฌ์ฉ ์์:
- ReSharper ์ค์น: JetBrains ReSharper๋ฅผ Visual Studio์ ์ค์นํฉ๋๋ค.
- ์ฝ๋ ๋ถ์ ์คํ: ReSharper ๋ฉ๋ด์์ "Inspect This"๋ฅผ ์ ํํ์ฌ ํ์ฌ ํ์ผ ๋๋ ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ๋ถ์ํฉ๋๋ค.
- ๋ฌธ์ ํด๊ฒฐ: ReSharper๊ฐ ๋ฐ๊ฒฌํ ๋ฌธ์ ๋ฅผ ๊ฒํ ํ๊ณ , ์๋ ์์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ๊ฒฐํฉ
์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ๊ฒฐํฉํ์ฌ ์ฝ๋ ํ์ง์ ๊ทน๋ํํ ์ ์์ต๋๋ค. ์ ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋ณธ์ ์ธ ์ฝ๋ ํ์ง ๊ฒ์ฌ๋ฅผ ์๋ํํ๊ณ , ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํตํด ๋ ๋ณต์กํ ๋ ผ๋ฆฌ์ ์ค๋ฅ์ ์ค๊ณ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ ์ฝ๋ ํ์ง์ ์ง์์ ์ผ๋ก ํฅ์์ํค๊ณ , ๊ฐ๋ฐ ์๋๋ฅผ ์ ์งํ๋ฉด์ ๋ฒ๊ทธ๋ฅผ ์ค์ด๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ํตํด ์ฝ๋ ํ์ง์ ํฅ์์ํค๊ณ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๋ฐฉ์งํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ํ์์ ์ธ ํ์ง ๊ด๋ฆฌ ๋๊ตฌ์ด๋ฉฐ, ์ด๋ฅผ ํตํด ๋ณด๋ค ๋์ ํ์ง์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๊ฒฝ๊ณ ํ ์คํธ์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ์ ๋ํด ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
19. ๊ฒฝ๊ณ ํ ์คํธ์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ
์๋ก : ์ด์ ํฌ์คํ ์์๋ ์ฝ๋ ๋ฆฌ๋ทฐ์ ์ ์ ์ฝ๋ ๋ถ์์ ํตํด ์ฝ๋ ํ์ง์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ๊ฒฝ๊ณ ํ ์คํธ์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ฅผ ํตํด ์ฝ๋์ ์์ ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ๊ฒฝ๊ณ ํ ์คํธ๋ ์ ๋ ฅ ๋ฐ์ดํฐ์ ๊ฒฝ๊ณ ๊ฐ์ ํ ์คํธํ์ฌ ์์ธ์ ์ธ ์ํฉ์์๋ ์์คํ ์ด ์์ ์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ํ, ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ ์ฝ๋๋ฅผ ๋ ๋ฆฝ์ ์ธ ๋ชจ๋๋ก ๋๋์ด ์ ์ง ๋ณด์์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๋ ๊ธฐ๋ฒ์ ๋๋ค.
๊ฒฝ๊ณ ํ ์คํธ์ ์ค์์ฑ
๊ฒฝ๊ณ ํ ์คํธ๋ ์ ๋ ฅ ๋ฐ์ดํฐ์ ๊ฒฝ๊ณ ๊ฐ, ์ฆ ์ต๋๊ฐ, ์ต์๊ฐ, ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ฃผ๋ณ์ ๊ฐ๋ค์ ํ ์คํธํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ด๋ ์์คํ ์ด ์์์น ๋ชปํ ์ ๋ ฅ์๋ ์์ ์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๊ฒฝ๊ณ ํ ์คํธ์ ์ฃผ์ ๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์๋ฌ ๋ฐ๊ฒฌ: ๊ฒฝ๊ณ ๊ฐ์์ ๋ฐ์ํ ์ ์๋ ์๋ฌ๋ฅผ ์ฌ์ ์ ๋ฐ๊ฒฌํ์ฌ ์์คํ ์ ์ ๋ขฐ์ฑ์ ๋์ ๋๋ค.
- ์์ ์ฑ ๊ฒ์ฆ: ๊ฒฝ๊ณ ๊ฐ์ ํ ์คํธํจ์ผ๋ก์จ ์์คํ ์ด ๊ทน๋จ์ ์ธ ์ํฉ์์๋ ์์ ์ ์ผ๋ก ๋์ํ๋์ง ๊ฒ์ฆํฉ๋๋ค.
- ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ํฅ์: ๊ฒฝ๊ณ ๊ฐ์ ํฌํจํ ๋ค์ํ ์ ๋ ฅ์ ํ ์คํธํ์ฌ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ํฅ์์ํต๋๋ค.
ํจ๊ณผ์ ์ธ ๊ฒฝ๊ณ ํ ์คํธ ๋ฐฉ๋ฒ
ํจ๊ณผ์ ์ธ ๊ฒฝ๊ณ ํ ์คํธ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- ๊ฒฝ๊ณ ๊ฐ ์๋ณ: ํ ์คํธํ ์ ๋ ฅ ๋ฐ์ดํฐ์ ๊ฒฝ๊ณ ๊ฐ์ ์๋ณํฉ๋๋ค. ์ด๋ ์ต์๊ฐ, ์ต๋๊ฐ, ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ฃผ๋ณ์ ๊ฐ๋ค์ ํฌํจํฉ๋๋ค.
- ํ ์คํธ ์ผ์ด์ค ์์ฑ: ๊ฐ ๊ฒฝ๊ณ ๊ฐ์ ํ ์คํธํ๋ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐฐ์ด์ ๊ธธ์ด๋ฅผ ํ ์คํธํ ๋๋ ๊ธธ์ด๊ฐ 0์ธ ๊ฒฝ์ฐ, ์ต๋ ๊ธธ์ด์ธ ๊ฒฝ์ฐ, ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ณด๋ค 1 ์์ ๊ฒฝ์ฐ์ ํฐ ๊ฒฝ์ฐ๋ฅผ ํ ์คํธํฉ๋๋ค.
- ์๋ํ ํ ์คํธ: ํ ์คํธ ์ผ์ด์ค๋ฅผ ์๋ํํ์ฌ ์ง์์ ์ผ๋ก ์คํํ ์ ์๋๋ก ํฉ๋๋ค. ์ด๋ ์ง์์ ์ธ ํตํฉ(CI) ํ๊ฒฝ์์ ํนํ ์ ์ฉํฉ๋๋ค.
๊ฒฝ๊ณ ํ ์คํธ ์์
๋ค์์ ๋ฐฐ์ด์ ๊ธธ์ด๋ฅผ ํ ์คํธํ๋ ๊ฒฝ๊ณ ํ ์คํธ์ ์์์ ๋๋ค:
csharp์ฝ๋ ๋ณต์ฌ
using System;
using Xunit;
public class ArrayTests
{
[Fact]
public void TestArrayBoundaryValues()
{
// ์ต์๊ฐ ํ
์คํธ
int[] array = new int[0];
Assert.Equal(0, array.Length);
// ์ต๋๊ฐ ํ
์คํธ (์๋ฅผ ๋ค์ด, ์ต๋ ๊ธธ์ด๊ฐ 100์ธ ๊ฒฝ์ฐ)
array = new int[100];
Assert.Equal(100, array.Length);
// ๊ทธ๋ณด๋ค 1 ์์ ๊ฐ ํ
์คํธ
array = new int[99];
Assert.Equal(99, array.Length);
// ๊ทธ๋ณด๋ค 1 ํฐ ๊ฐ ํ
์คํธ
array = new int[101];
Assert.Equal(101, array.Length);
}
}
์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ
์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ ์ฝ๋๋ฅผ ๋ ๋ฆฝ์ ์ธ ๋ชจ๋๋ก ๋๋์ด ์ ์ง ๋ณด์์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ด๋ ๋๊ท๋ชจ ์์คํ ์์ ํนํ ์ค์ํ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ์ ๊ณตํฉ๋๋ค:
- ์ ์ง ๋ณด์์ฑ ํฅ์: ์ฝ๋๋ฅผ ๋ ๋ฆฝ์ ์ธ ๋ชจ๋๋ก ๋๋๋ฉด ๊ฐ ๋ชจ๋์ ๋ ๋ฆฝ์ ์ผ๋ก ์์ ํ๊ณ ํ ์คํธํ ์ ์์ด ์ ์ง ๋ณด์์ฑ์ด ํฅ์๋ฉ๋๋ค.
- ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ: ๋ ๋ฆฝ์ ์ธ ๋ชจ๋์ ๋ค๋ฅธ ํ๋ก์ ํธ๋ ์์คํ ์์๋ ์ฌ์ฌ์ฉํ ์ ์์ด ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ ๋์ ๋๋ค.
- ๋ณต์ก๋ ๊ฐ์: ์์คํ ์ ์์ ๋ชจ๋๋ก ๋๋๋ฉด ๊ฐ ๋ชจ๋์ ๋ณต์ก๋๊ฐ ์ค์ด๋ค์ด ์ ์ฒด ์์คํ ์ ๋ณต์ก๋๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ฌ์์ง๋๋ค.
ํจ๊ณผ์ ์ธ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ ๋ฐฉ๋ฒ
ํจ๊ณผ์ ์ธ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- ๋จ์ผ ์ฑ ์ ์์น: ๊ฐ ๋ชจ๋์ ๋จ์ผํ ์ฑ ์์ ๊ฐ์ ธ์ผ ํฉ๋๋ค. ์ด๋ ๊ฐ ๋ชจ๋์ด ํ๋์ ๊ธฐ๋ฅ๋ง์ ์ํํ๋๋ก ์ค๊ณํ๋ ๊ฒ์ ๋๋ค.
- ์ธํฐํ์ด์ค ์ฌ์ฉ: ๋ชจ๋ ๊ฐ์ ์์กด์ฑ์ ์ต์ํํ๊ธฐ ์ํด ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ๋ชจ๋ ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์ ์ฐ์ฑ์ ๋์ ๋๋ค.
- ๋ชจ๋ํ๋ ๊ตฌ์กฐ: ํ๋ก์ ํธ๋ฅผ ๋ชจ๋ํ๋ ๊ตฌ์กฐ๋ก ์ค๊ณํ์ฌ ๊ฐ ๋ชจ๋์ด ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ ์ ์๋๋ก ํฉ๋๋ค. ์ด๋ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ์ ๋ค์์คํ์ด์ค๋ฅผ ํตํด ๊ตฌํํ ์ ์์ต๋๋ค.
์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ ์์
๋ค์์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ์ ์์์ ๋๋ค. ์ฌ๊ธฐ์๋ ๋ฐ์ดํฐ ์ก์ธ์ค ๋ก์ง๊ณผ ๋น์ฆ๋์ค ๋ก์ง์ ๋ถ๋ฆฌํ์ฌ ๋ชจ๋ํํฉ๋๋ค.
IDataAccess.cs:
csharp์ฝ๋ ๋ณต์ฌ
public interface IDataAccess
{
void AddData(string data);
string GetData(int id);
}
DataAccess.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class DataAccess : IDataAccess
{
private readonly Dictionary<int, string> _database = new Dictionary<int, string>();
public void AddData(string data)
{
int id = _database.Count + 1;
_database.Add(id, data);
}
public string GetData(int id)
{
_database.TryGetValue(id, out string data);
return data;
}
}
BusinessLogic.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class BusinessLogic
{
private readonly IDataAccess _dataAccess;
public BusinessLogic(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void ProcessData(string data)
{
_dataAccess.AddData(data);
string retrievedData = _dataAccess.GetData(1);
Console.WriteLine($"Processed Data: {retrievedData}");
}
}
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
IDataAccess dataAccess = new DataAccess();
BusinessLogic businessLogic = new BusinessLogic(dataAccess);
businessLogic.ProcessData("Sample Data");
}
}
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ๊ฒฝ๊ณ ํ ์คํธ์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ฅผ ํตํด ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ๊ฒฝ๊ณ ํ ์คํธ๋ฅผ ํตํด ๊ทน๋จ์ ์ธ ์ ๋ ฅ ๊ฐ์์๋ ์์คํ ์ด ์์ ์ ์ผ๋ก ๋์ํ๋์ง ๊ฒ์ฆํ๊ณ , ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ฅผ ํตํด ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ์์กด์ฑ ์ฃผ์ ๊ณผ ๋์์ธ ํจํด์ ํตํด ์ฝ๋๋ฅผ ๋์ฑ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
20. ์์กด์ฑ ์ฃผ์ ๊ณผ ๋์์ธ ํจํด์ ํตํ ์ฝ๋ ํจ์จ์ฑ ํฅ์
์๋ก : ์ด์ ํฌ์คํ ์์๋ ๊ฒฝ๊ณ ํ ์คํธ์ ์ฝ๋ ๋ถ๋ฆฌ ๋ฐ ๋ชจ๋ํ๋ฅผ ํตํด ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์์กด์ฑ ์ฃผ์ ๊ณผ ๋์์ธ ํจํด์ ํตํด ์ฝ๋์ ํจ์จ์ฑ์ ๋์ฑ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ์์กด์ฑ ์ฃผ์ ์ ๊ฐ์ฒด ๊ฐ์ ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ํ์ฌ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์ ์ฐ์ฑ์ ๋์ด๋ ๊ธฐ๋ฒ์ ๋๋ค. ๋์์ธ ํจํด์ ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํ์ฌ ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ํฅ์์ํต๋๋ค.
์์กด์ฑ ์ฃผ์ ์ ์ค์์ฑ
์์กด์ฑ ์ฃผ์ (Dependency Injection, DI)์ ๊ฐ์ฒด ๊ฐ์ ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ํ์ฌ ๊ฐ์ฒด ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ ๊ธฐ๋ฒ์ ๋๋ค. ์ด๋ ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ๋์ด๋ ๋ฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ์์กด์ฑ ์ฃผ์ ์ ์ฃผ์ ๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๊ฒฐํฉ๋ ๊ฐ์: ๊ฐ์ฒด ๊ฐ์ ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ํจ์ผ๋ก์จ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ , ์ฝ๋ ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ ์ํฅ์ ์ต์ํํฉ๋๋ค.
- ์ ์ฐ์ฑ ์ฆ๊ฐ: ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ๋ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ฅผ ์ฝ๊ฒ ๊ต์ฒดํ๊ฑฐ๋ ํ์ฅํ ์ ์์ด ์ ์ฐ์ฑ์ด ์ฆ๊ฐํฉ๋๋ค.
- ํ ์คํธ ์ฉ์ด์ฑ: ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ๋ฐ๊ธฐ ๋๋ฌธ์ ๋ชจ์ ๊ฐ์ฒด(Mock Object)๋ฅผ ์ฌ์ฉํ์ฌ ๋จ์ ํ ์คํธ๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์์ต๋๋ค.
์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ
์์กด์ฑ ์ฃผ์ ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ์ธ ๊ฐ์ง๋ก ๋๋ ์ ์์ต๋๋ค:
- ์์ฑ์ ์ฃผ์ : ์์ฑ์๋ฅผ ํตํด ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ฐ์ฅ ์ผ๋ฐ์ ์ด๋ฉฐ, ์์กด์ฑ์ ๋ช ํํ๊ฒ ํํํ ์ ์์ต๋๋ค.
- ์์ฑ ์ฃผ์ : ์์ฑ์ ํตํด ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ฃผ์ ๋ฐ์ ์์กด์ฑ์ด ์ ํ์ ์ผ ๋ ์ ์ฉํฉ๋๋ค.
- ๋ฉ์๋ ์ฃผ์ : ๋ฉ์๋๋ฅผ ํตํด ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํน์ ๋ฉ์๋ ํธ์ถ ์์ ์ ์์กด์ฑ์ ์ฃผ์ ๋ฐ์ ๋ ์ ์ฉํฉ๋๋ค.
์์กด์ฑ ์ฃผ์ ์์
๋ค์์ ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ์์์ ๋๋ค:
IDataAccess.cs:
csharp์ฝ๋ ๋ณต์ฌ
public interface IDataAccess
{
void AddData(string data);
string GetData(int id);
}
DataAccess.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class DataAccess : IDataAccess
{
private readonly Dictionary<int, string> _database = new Dictionary<int, string>();
public void AddData(string data)
{
int id = _database.Count + 1;
_database.Add(id, data);
}
public string GetData(int id)
{
_database.TryGetValue(id, out string data);
return data;
}
}
BusinessLogic.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class BusinessLogic
{
private readonly IDataAccess _dataAccess;
public BusinessLogic(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void ProcessData(string data)
{
_dataAccess.AddData(data);
string retrievedData = _dataAccess.GetData(1);
Console.WriteLine($"Processed Data: {retrievedData}");
}
}
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
IDataAccess dataAccess = new DataAccess();
BusinessLogic businessLogic = new BusinessLogic(dataAccess);
businessLogic.ProcessData("Sample Data");
}
}
๋์์ธ ํจํด์ ์ค์์ฑ
๋์์ธ ํจํด์ ์ํํธ์จ์ด ์ค๊ณ ์ ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํฉ๋๋ค. ๋์์ธ ํจํด์ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋์์ธ ํจํด์ ํฌ๊ฒ ์ธ ๊ฐ์ง ์ ํ์ผ๋ก ๋๋ ์ ์์ต๋๋ค:
- ์์ฑ ํจํด: ๊ฐ์ฒด ์์ฑ๊ณผ ๊ด๋ จ๋ ํจํด์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฑ๊ธํค ํจํด, ํฉํ ๋ฆฌ ํจํด ๋ฑ์ด ์์ต๋๋ค.
- ๊ตฌ์กฐ ํจํด: ๊ฐ์ฒด ๊ฐ์ ๊ด๊ณ๋ฅผ ๊ตฌ์ฑํ๋ ํจํด์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ด๋ํฐ ํจํด, ๋ฐ์ฝ๋ ์ดํฐ ํจํด ๋ฑ์ด ์์ต๋๋ค.
- ํ์ ํจํด: ๊ฐ์ฒด ๊ฐ์ ์ํธ์์ฉ์ ์ ์ํ๋ ํจํด์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ต์ ๋ฒ ํจํด, ์ ๋ต ํจํด ๋ฑ์ด ์์ต๋๋ค.
๋์์ธ ํจํด ์์
๋ค์์ ์ฑ๊ธํค ํจํด์ ์ฌ์ฉํ์ฌ ๋จ์ผ ์ธ์คํด์ค๋ฅผ ๋ณด์ฅํ๋ ์์์ ๋๋ค:
Singleton.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Singleton
{
private static Singleton _instance;
private static readonly object _lock = new object();
private Singleton() { }
public static Singleton Instance
{
get
{
lock (_lock)
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
}
public void DoSomething()
{
Console.WriteLine("Singleton instance doing something.");
}
}
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
Singleton instance1 = Singleton.Instance;
Singleton instance2 = Singleton.Instance;
instance1.DoSomething();
instance2.DoSomething();
Console.WriteLine(ReferenceEquals(instance1, instance2)); // True
}
}
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ์์กด์ฑ ์ฃผ์ ๊ณผ ๋์์ธ ํจํด์ ํตํด ์ฝ๋์ ํจ์จ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์์กด์ฑ ์ฃผ์ ์ ํตํด ๊ฐ์ฒด ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์ ์ฐ์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ๋์ผ ์ ์์ผ๋ฉฐ, ๋์์ธ ํจํด์ ํตํด ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํ์ฌ ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง ๋ณด์์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ๋์ฑ ์ฌํ๋ ๋์์ธ ํจํด๊ณผ ํ ์คํธ ๊ธฐ๋ฒ์ ๋ค๋ฃจ์ด ์ฝ๋ ํ์ง์ ๋์ฑ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
21. ๊ณ ๊ธ ๋์์ธ ํจํด๊ณผ ํ ์คํธ ๊ธฐ๋ฒ
์๋ก : ์ด์ ํฌ์คํ ์์๋ ์์กด์ฑ ์ฃผ์ ๊ณผ ๋์์ธ ํจํด์ ํตํด ์ฝ๋์ ํจ์จ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ๋ณด๋ค ์ฌํ๋ ๋์์ธ ํจํด๊ณผ ํ ์คํธ ๊ธฐ๋ฒ์ ํตํด ์ฝ๋ ํ์ง์ ๋์ฑ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค. ๊ณ ๊ธ ๋์์ธ ํจํด์ ๋ณต์กํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ฝ๋๋ฅผ ๋์ฑ ์ ์ฐํ๊ณ ์ ์ง ๋ณด์ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค. ๋ํ, ํ ์คํธ ๊ธฐ๋ฒ์ ํตํด ์ฝ๋์ ์ ๋ขฐ์ฑ์ ๋์ด๊ณ ๋ฒ๊ทธ๋ฅผ ์ฌ์ ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๊ณ ๊ธ ๋์์ธ ํจํด
1. ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด
ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ๊ฐ์ฒด ์์ฑ ๋ก์ง์ ๋ณ๋์ ๋ฉ์๋๋ก ๋ถ๋ฆฌํ์ฌ ์ฝ๋์ ์ ์ฐ์ฑ์ ๋์ด๋ ํจํด์ ๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ์ฒด ์์ฑ ๋ฐฉ์์ ์๋ธํด๋์ค์์ ์ ์ํ ์ ์์ต๋๋ค.
IProduct.cs:
csharp์ฝ๋ ๋ณต์ฌ
public interface IProduct
{
void Operate();
}
ConcreteProductA.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteProductA : IProduct
{
public void Operate()
{
Console.WriteLine("ConcreteProductA is operating.");
}
}
ConcreteProductB.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteProductB : IProduct
{
public void Operate()
{
Console.WriteLine("ConcreteProductB is operating.");
}
}
Creator.cs:
csharp์ฝ๋ ๋ณต์ฌ
public abstract class Creator
{
public abstract IProduct FactoryMethod();
public void Operation()
{
var product = FactoryMethod();
product.Operate();
}
}
ConcreteCreatorA.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteCreatorA : Creator
{
public override IProduct FactoryMethod()
{
return new ConcreteProductA();
}
}
ConcreteCreatorB.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteCreatorB : Creator
{
public override IProduct FactoryMethod()
{
return new ConcreteProductB();
}
}
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
Creator creatorA = new ConcreteCreatorA();
creatorA.Operation();
Creator creatorB = new ConcreteCreatorB();
creatorB.Operation();
}
}
2. ์ ๋ต ํจํด
์ ๋ต ํจํด์ ์๊ณ ๋ฆฌ์ฆ์ ์บก์ํํ์ฌ ๋ฐํ์์ ๊ต์ฒดํ ์ ์๋๋ก ํ๋ ํจํด์ ๋๋ค. ์ด๋ฅผ ํตํด ์๋ก ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ์ ์ฝ๊ฒ ๊ต์ฒดํ๊ณ ํ์ฅํ ์ ์์ต๋๋ค.
IStrategy.cs:
csharp์ฝ๋ ๋ณต์ฌ
public interface IStrategy
{
void Execute();
}
ConcreteStrategyA.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteStrategyA : IStrategy
{
public void Execute()
{
Console.WriteLine("ConcreteStrategyA executed.");
}
}
ConcreteStrategyB.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class ConcreteStrategyB : IStrategy
{
public void Execute()
{
Console.WriteLine("ConcreteStrategyB executed.");
}
}
Context.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Context
{
private IStrategy _strategy;
public void SetStrategy(IStrategy strategy)
{
_strategy = strategy;
}
public void ExecuteStrategy()
{
_strategy.Execute();
}
}
Program.cs:
csharp์ฝ๋ ๋ณต์ฌ
public class Program
{
public static void Main(string[] args)
{
var context = new Context();
context.SetStrategy(new ConcreteStrategyA());
context.ExecuteStrategy();
context.SetStrategy(new ConcreteStrategyB());
context.ExecuteStrategy();
}
}
๊ณ ๊ธ ํ ์คํธ ๊ธฐ๋ฒ
1. ํตํฉ ํ ์คํธ
ํตํฉ ํ ์คํธ๋ ์ฌ๋ฌ ๋ชจ๋์ ํตํฉํ์ฌ ์ ์ฒด ์์คํ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ๊ฒ์ฆํ๋ ํ ์คํธ์ ๋๋ค. ์ด๋ฅผ ํตํด ๋ชจ๋ ๊ฐ์ ์ํธ์์ฉ์์ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ฌ์ ์ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
ํตํฉ ํ ์คํธ ์์:
csharp์ฝ๋ ๋ณต์ฌ
public class IntegrationTest
{
[Fact]
public async Task Test_Adding_WorkInstruction()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "TestDatabase")
.Options;
using (var context = new AppDbContext(options))
{
var service = new WorkInstructionService(context, Mock.Of<ILogger<WorkInstructionService>>());
var workInstruction = new WorkInstruction
{
TaskName = "TestTask",
Content = "TestContent",
Date = DateTime.Now,
Writer = "TestWriter",
Priority = "High",
IsCompleted = false
};
await service.AddWorkInstructionAsync(workInstruction);
var result = await service.GetWorkInstructionByTaskNameAsync("TestTask");
Assert.NotNull(result);
Assert.Equal("TestTask", result.TaskName);
}
}
}
2. ์ฑ๋ฅ ํ ์คํธ
์ฑ๋ฅ ํ ์คํธ๋ ์์คํ ์ ์ฑ๋ฅ์ ์ธก์ ํ๊ณ ๋ณ๋ชฉ ํ์์ ์ฐพ์๋ด๋ ํ ์คํธ์ ๋๋ค. ์ด๋ฅผ ํตํด ์์คํ ์ ์๋ต ์๊ฐ, ์ฒ๋ฆฌ๋, ์์ ์ฑ์ ํ๊ฐํ ์ ์์ต๋๋ค.
์ฑ๋ฅ ํ ์คํธ ๋๊ตฌ:
- JMeter: ๋ค์ํ ์ฑ๋ฅ ํ ์คํธ ์๋๋ฆฌ์ค๋ฅผ ์ค์ ํ๊ณ ์คํํ ์ ์๋ ์คํ ์์ค ๋๊ตฌ์ ๋๋ค.
- LoadRunner: ๋ค์ํ ํ๋กํ ์ฝ์ ์ง์ํ๋ฉฐ, ๋ณต์กํ ์ฑ๋ฅ ํ ์คํธ๋ฅผ ์๋ํํ ์ ์๋ ์์ฉ ๋๊ตฌ์ ๋๋ค.
๊ฒฐ๋ก
์ด๋ฒ ํฌ์คํ ์์๋ ๊ณ ๊ธ ๋์์ธ ํจํด๊ณผ ํ ์คํธ ๊ธฐ๋ฒ์ ํตํด ์ฝ๋์ ํ์ง์ ๋์ฑ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด๊ณผ ์ ๋ต ํจํด์ ์ฌ์ฉํ์ฌ ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ํ์ฅ์ฑ์ ๋์ผ ์ ์์ผ๋ฉฐ, ํตํฉ ํ ์คํธ์ ์ฑ๋ฅ ํ ์คํธ๋ฅผ ํตํด ์์คํ ์ ์ ๋ขฐ์ฑ๊ณผ ์ฑ๋ฅ์ ๋ณด์ฅํ ์ ์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ ์ค์ ํ๋ก์ ํธ์์ ์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ์ ์ฉํ ์ฌ๋ก๋ฅผ ํตํด ๊ตฌ์ฒด์ ์ธ ํ์ฉ ๋ฐฉ์์ ์์๋ณด๊ฒ ์ต๋๋ค.