---
# System prepended metadata

title: 202002 TrendMicro

---

# 202002 TrendMicro

# Code Commits
## Create Budgets

### CreateBudgets.feature

    Feature: CreateBudgets
            In order to manage budget of department
            As a department manager
            I want to set budget amount of specific year month
    
    Scenario: create a budget
            Given budget for setting
                    | YearMonth | Amount |
                    | 202003    | 31     |
            When I create
            Then it should be created successfully
            And there should be budgets existed
                    | YearMonth | Amount |
                    | 202003    | 31     |

### CreateBudgetsSteps.cs

        [Binding]
        public class CreateBudgetsSteps : Steps
        {
            private static CreateBudgetsPage _createBudgetsPage;
            private CreateBudgetResultPage _createBudgetResultPage;
    
            [BeforeTestRun]
            public static void SetUpTestRun()
            {
                AtataContext.GlobalConfiguration.UseChrome().
                             //WithArguments("start-maximized").
                             WithLocalDriverPath().UseBaseUrl("http://localhost:50564/").UseCulture("en-us")
                             .UseAllNUnitFeatures();
            }
    
            [BeforeScenario]
            public static void SetUpScenario()
            {
                AtataContext.Configure().Build();
    
                _createBudgetsPage = Go.To<CreateBudgetsPage>();
            }
    
            [AfterScenario]
            public static void TearDownScenario()
            {
                AtataContext.Current?.CleanUp();
            }
    
            [Given(@"budget for setting")]
            public void GivenBudgetForSetting(Table table)
            {
                var budget = table.CreateInstance<Budget>();
                ScenarioContext.Set(budget);
            }
    
            [When(@"I create")]
            public void WhenICreate()
            {
                var budget = ScenarioContext.Get<Budget>();
                _createBudgetResultPage = _createBudgetsPage.Create(budget);
            }
    
            [Then(@"it should be created succeed")]
            public void ThenItShouldBeCreatedSuccessfully()
            {
                _createBudgetResultPage.Status.Should.ContainAll("created", "succeed");
            }
    
            [Then(@"there should be budgets existed")]
            public void ThenThereShouldBeBudgetsExisted(Table table)
            {
                using (var dbContext = new AccountingEntitiesForTest())
                {
                    var budgets = dbContext.Budgets.ToList();
                    table.CompareToSet(budgets);
                }
            }
        }

### CreateBudgetsPage.cs

        using _ = CreateBudgetsPage;
    
        [Url("budgets/create")]
        public class CreateBudgetsPage : Page<_>
        {
            public CreateBudgetResultPage Create(Budget budget)
            {
                return this
                       .YearMonth.Set(budget.YearMonth)
                       .Amount.Set(budget.Amount)
                       .CreateBudget.ClickAndGo();
            }
    
            [FindByName("Create")] public Button<CreateBudgetResultPage, _> CreateBudget { get; set; }
            [FindByName("Amount")] public NumberInput<_> Amount { get; set; }
            [FindByName("YearMonth")] public TextInput<_> YearMonth { get; set; }
        }

### CreateBudgetResultPage.cs

        using _ = CreateBudgetResultPage;
        public class CreateBudgetResultPage : Page<_>
        {
            [FindByName("Status")]
            public Text<_> Status { get; set; }
        }

### BudgetsController.cs

        public class BudgetsController : Controller
        {
            [HttpGet]
            public ActionResult Create()
            {
                return View();
            }
    
            [HttpPost]
            public ActionResult CreateBudgets()
            {
                return View();
            }
        }

### Create.cshtml

    @{
        ViewBag.Title = "Create";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <h2>Create</h2>
    
    @using (Html.BeginForm("CreateBudgets", "Budgets", FormMethod.Post))
    {
        <div>
            YearMonth: <input type="text" name="YearMonth"/>
        </div>
        <div>
            Amount: <input type="number" name="Amount"/>
        </div>
        <input type="submit" value="Create" name="Create"/>
    }

### CreateBudgets.cshtml

    
    @{
        ViewBag.Title = "CreateBudgets";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <h2>CreateBudgets</h2>
    
    <p name="Status">budget created succeed!</p>


## Add Unit Test Project for TDD

Install nuget packages

- NSubstitute
- FluentAssertions

### BudgetsControllerTests.cs

        [TestFixture()]
        public class BudgetsControllerTests
        {
            [Test()]
            public void create_a_budget_should_invoke_budgetService_save()
            {
                var budgetService = Substitute.For<IBudgetService>();
    
                var budgetsController = new BudgetsController(budgetService);
                budgetsController.CreateBudgets("202003", 31m);
    
                budgetService.Received().Save("202003", 31m);
            }
        }

### BudgetController.cs CreateBudgets()

        public class BudgetsController : Controller
        {
            private readonly IBudgetService _budgetService;
    
            public BudgetsController(IBudgetService budgetService)
            {
                _budgetService = budgetService;
            }
    
            [HttpPost]
            public ActionResult CreateBudgets(string yearMonth, decimal amount)
            {
                _budgetService.Save(yearMonth, amount); 
                return View();
            } 
        }

### Add a Failed Unit Test: create a budget succeed

            [Test]
            public void create_a_budget_succeed()
            {
                var viewResult = _budgetsController.CreateBudgets("202003", 31m) as ViewResult;
                (viewResult.ViewBag.Status as string).Should().ContainAll("created", "succeed");
            }

### Add a Constructor of BudgetsController to Initialize BudgetService

        public class BudgetsController : Controller
        {
            private readonly IBudgetService _budgetService;
    
            public BudgetsController()
            {
                _budgetService = new BudgetService();
            }
    
            public BudgetsController(IBudgetService budgetService)
            {
                _budgetService = budgetService;
            }
        }

### BudgetService.cs

    public class BudgetService : IBudgetService
    {
        public void Save(string yearMonth, decimal amount)
        {
            Console.WriteLine("todo");
        }
    }
    
### Add Entities from EF in Web Application
![](https://i.imgur.com/rorjgyO.png)
### BudgetService.Save() using DbContext to Insert a Budget

        public class BudgetService : IBudgetService
        {
            public void Save(string yearMonth, decimal amount)
            {
                using (var dbContext = new AccountingEntities())
                {
                    dbContext.Budgets.Add(new Budget() { YearMonth = yearMonth, Amount = amount });
                    dbContext.SaveChanges();
                } 
            }
        }


### Can’t Repeat Acceptance Test Because of Insert Duplicate PKey Budget
![](https://i.imgur.com/R2dhNro.png)

### Clean Budgets Table Data Before Scenario Running

            [BeforeScenario]
            public static void SetUpScenario()
            {
                AtataContext.Configure().Build();
    
                using (var dbContext = new AccountingEntitiesForTest())
                {
                    dbContext.Database.ExecuteSqlCommand("TRUNCATE TABLE [Budgets]");
                } 
    
                _createBudgetsPage = Go.To<CreateBudgetsPage>();
            } 


## Update the Budget When Budget Existed

### Scenario: update the budget when budget existed


    Scenario: update the budget when budget existed
            Given budget for setting
                    | YearMonth | Amount |
                    | 202003    | 310    |
            And there are budgets
                    | YearMonth | Amount |
                    | 202003    | 31     |
            When I create
            Then it should be updated succeed
            And there should be budgets existed
                    | YearMonth | Amount |
                    | 202003    | 310    |

### New Steps for Initialized Budget Data and Assertion for Updated Status 

            [Given(@"there are budgets")]
            public void GivenThereAreBudgets(Table table)
            {
                using (var dbContext = new AccountingEntitiesForTest())
                {
                    var budgets = table.CreateSet<Budget>();
                    dbContext.Budgets.AddRange(budgets);
                    dbContext.SaveChanges();
                } 
            }
    
            [Then(@"it should be updated succeed")]
            public void ThenItShouldBeUpdatedSucceed()
            {
                _createBudgetResultPage.Status.Should.ContainAll("updated", "succeed");
            }

### Add a Unit Test for BudgetsController: update the budget when budget existed

            [Test]
            public void update_the_budget_when_budget_existed()
            {
                _budgetService.Save(Arg.Any<string>(), Arg.Any<decimal>())
                              .ReturnsForAnyArgs(true);
    
                var viewResult = _budgetsController.CreateBudgets("202003", 31m) as ViewResult;
                (viewResult.ViewBag.Status as string).Should().ContainAll("updated", "succeed");
            }

### Complete BudgetsController.CreateBudgets() when update the budget

            [HttpPost]
            public ActionResult CreateBudgets(string yearMonth, decimal amount)
            {
                var isUpdated = _budgetService.Save(yearMonth, amount);
                ViewBag.Status = isUpdated ? "budget updated succeed!" : "budget created succeed!";
    
                return View();
            }

### Complete BudgetService.Save() when update and insert budget

        public class BudgetService : IBudgetService
        {
            public bool Save(string yearMonth, decimal amount)
            {
                using (var dbContext = new AccountingEntities())
                {
                    var budget = dbContext.Budgets.Find(yearMonth);
                    var isBudgetExisted = budget != null;
                    if (isBudgetExisted)
                    {
                        budget.Amount = amount;
                    }
                    else
                    {
                        dbContext.Budgets.Add(new Budget() { YearMonth = yearMonth, Amount = amount });
                    }
                    dbContext.SaveChanges();
                    return isBudgetExisted;
                } 
            }
        }

## Query Budgets
### QueryBudgets.Feature

    Feature: QueryBudgets
            In order to control budgets
            As a manager
            I want to query total amount of a period
    
    Scenario: no budgets
            When I query between "20200401" and "20200401"
            Then the total amount should be 0.00
            
### QueryBudgetSteps
```
    [Binding]
    [Scope(Feature = "QueryBudgets")]
    public class QueryBudgetsSteps : Steps
    {
        private QueryBudgetPage _queryBudgetPage;

        [BeforeScenario()]
        public void BeforeScenario()
        {
            AtataContext.Configure()
                        .UseChrome()
                        .UseBaseUrl("http://localhost:50564/")
                        .UseCulture("en-us").UseNUnitTestName()
                        .AddNUnitTestContextLogging().LogNUnitError()
                        .UseAssertionExceptionType<NUnit.Framework.AssertionException>()
                        .UseNUnitAggregateAssertionStrategy().Build();

            _queryBudgetPage = Go.To<QueryBudgetPage>();
        }

        [AfterScenario()]
        public void AfterScenario()
        {
            AtataContext.Current?.CleanUp();
        }

        [When(@"I query between ""(.*)"" and ""(.*)""")]
        public void WhenIQueryBetweenAnd(string start, string end)
        {
            _queryBudgetPage.Query(start, end);
        }

        [Then(@"the total amount should be (.*)")]
        public void ThenTheTotalAmountShouldBe(string expectedAmount)
        {
            _queryBudgetPage.TotalAmount.Should.Equal(expectedAmount);
        }
    }
```
            
### QueryBudgetPage.cs
```
    using _ = QueryBudgetPage;

    [Url("budgets/query")]
    public class QueryBudgetPage : Page<_>
    {
        public void Query(string start, string end)
        {
            this
                .Start.Set(start)
                .End.Set(end)
                .QueryBudget.Click();
        }

        [FindByName("Query")] public Button<_> QueryBudget { get; set; }
        [FindByName("End")] public TextInput<_> End { get; set; }
        [FindByName("Start")] public TextInput<_> Start { get; set; }
        [FindByName("TotalAmount")] public Text<_> TotalAmount { get; set; }
    }
```

### BudgetsController.cs
```
    public class BudgetsController : Controller
    {
        private readonly IBudgetManager _budgetManager;

        public BudgetsController()
        {
            _budgetManager = new BudgetManager();
        }

        public BudgetsController(IBudgetManager budgetManager)
        {
            _budgetManager = budgetManager;
        }

        // GET: Budgets
        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult CreateBudget(string yearMonth, decimal amount)
        {
            var isUpdated = _budgetManager.Save(yearMonth, amount);

            if (isUpdated)
            {
                ViewBag.Status = "budget updated succeed";
            }
            else
            {
                ViewBag.Status = "budget created succeed";
            }

            return View();
        }

        [HttpGet]
        public ActionResult Query()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Query(QueryBudgetViewModel queryBudgetViewModel)
        {
            return View(queryBudgetViewModel);
        } 
    }
```

### [View] Query.cshtml
```
@model AccountingWeb.ViewModels.QueryBudgetViewModel

@{
    ViewBag.Title = "Query";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Query</h2>

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>QueryBudgetViewModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Start, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Start, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Start, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.End, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.End, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.End, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-10">
                <p name="TotalAmount">
                    @if (Model != null)
                    {
                        @Model.TotalAmount.ToString("F2")
                    }
                </p>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Query" name="Query" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

```

### QueryBudgetViewModel.cs
```
    public class QueryBudgetViewModel
    {
        public string Start { get; set; }
        public string End { get; set; }
        public decimal TotalAmount { get; set; }
    }
```

### BudgetsControllerTests.cs
```
        [Test]
        public void query_budgets()
        {
            _budgetManager.TotalAmount(
                new DateTime(2020, 4, 1),
                new DateTime(2020, 4, 1)
                ).Returns(91m);

            var viewResult = _budgetsController.Query(new QueryBudgetViewModel
            {
                Start = "20200401",
                End = "20200401"
            }) as ViewResult;

            (viewResult.Model as QueryBudgetViewModel)
                .TotalAmount.Should().Be(91m);
        }
```

### BudgetsController.cs
```
        [HttpPost]
        public ActionResult Query(QueryBudgetViewModel queryBudgetViewModel)
        {
            var start = DateTime.ParseExact( queryBudgetViewModel.Start,
                                                "yyyyMMdd", null);
            var end = DateTime.ParseExact( queryBudgetViewModel.End,
                                                "yyyyMMdd", null);

            var totalAmount = _budgetManager.TotalAmount(start, end);
            queryBudgetViewModel.TotalAmount = totalAmount;
            return View(queryBudgetViewModel);
        } 

```

### BudgetManager.cs
```
        public decimal TotalAmount(DateTime start, DateTime end)
        {
            throw new NotImplementedException();
        }

```

