Software Gardening

.NET, web, community, architecture, practices

Page 2 of 2

Utah Code Camp 2014

Last Saturday I pulled double duty at Utah Code Camp. First, as an organizer, I was busy helping sponsors, attendees, speakers, and volunteers. I think this was the best Code Camp we’ve ever had with close to 900 attendees! Thank you to everyone that was there.

As someone that speaks at lots of code camps, I tried to look at Utah Code Camp with some impartiality, comparing this event to others. First, the lunch was outstanding. Jason’s Deli was a great choice. The venue was the best I’ve seen.

I had two sessions, the first was “Lightswitch: Visual Studio’s Hidden Secret”. You can find the slides here. The second was “Unit Testing ASP.Net MVC”. You can download the slides and demo code. Be sure to checkout my eight part blog series on MVC unit testing.

Coming up, I’ll be at Boise Code Camp on April 6 speaking on Unit Testing ASP.Net MVC.

Source: CraigBerntson

Book Review: Building UIs with Wijmo

Building great user interfaces for a desktop app isn’t easy. Build great web user interfaces is even harder. We using things like bootstrap or jQueryUI to make things easier. Have you ever looked at Wijmo? Wijmo is built on top of and extends jQuery UI. It comes in two versions, a free one that has a minimal, but usable set of widgets and a Professional edition that has really cool things like SVG graphs, a data grid, and even a web-based spreadsheet. You can even purchase a support contract that lets you pick up the phone and call someone when you get stuck. Wijmo is a product of ComponentOne. (Disclaimer: I do not work for ComponentOne, but I am a ComponentOne Community Influencer).

While Wijmo is pretty easy to pickup and use, like any technology, there are some tricky areas and gotchas. The book, “Building UIs with Wijmo” by Yuguang Zhang and published by Packt Publishing points out some of those areas, but also give you some basics to get you going quickly.

The book starts with an explanation of Wijmo and how to install then quickly moves into a simple widget, the Dialog. It provides a good explanation of how the Wijmo dialog differs from the one in jQueryUI and how to take advantage of the differences. It even discusses loading external content into the Wijmo dialog’s IFrame.

Chapter 3 then discusses some of the form controls, particularly the Checkbox, Radio Button, and DropDown controls. There is a good comment about radio buttons that look like command buttons causing confusion to users (I’ve had trouble with these myself) and a good example for the DropDown control listing continents with countries nested underneath each one.

Chapter 4 discusses working with images and provides some configuration tips for the Carousel.

Chapters 5 through 8 move into more advanced topics and cover things like tooltips and using Wijmo themes for HTML5 video. Chapter 6 discusses building a dashboard using Wijmo and Knockout.js. While the explanation of Knockout is good, I found it lacking some information for beginners. In the two sample forms, it would have been better to show the finished product before discussing the code.

Chapter 7 talks about mobile applications and how to use the Wijmo AppView to make one application that is reactive and works on both desktop and mobile browsers.

The final chapter shows how to spelunk into the javascript code that is used for Wijmo and change its behavior and add features. It then discusses bringing the Wijm0 CSS themes into Themeroller to modify them.

There were some formatting issues in a few places where spaces were missing between words. Also, the writing did use action tense. For example, the author said, “I would encourage you” instead of “I encourage you”. This should have been caught in editing. The book provides a quick overview for some Wijmo components. There is no discussion of the most interesting part of Wijmo, the Professional edition. There was also nothing about Wijmo’s support of Angular. Overall, I’m not sure if the book adds much value as the Wijmo documentation and samples provided by the Wijmo team at ComponentOne are very good.

 

Source: CraigBerntson

DevConnections & Silicon Valley Code Camp Followup

I’ve been remiss in not getting this but just after I got home, I injured my back and was flat in bed for several days. After that I was catching up at work.

First, thank you for attending my sessions. Second (ok, also tied for first), it was great to meet many of you and hear about your development processes and issues.

Slides and demo code are available now on my Presentations page.

In my MVC Unit Testing session, I used Ninject to show how to do Dependency Injection. But I also mentioned that Ninject turns out to be one of the slowest DI tools available. Here’s the link to the speed tests.

Source: CraigBerntson

Unit Testing ASP.Net MVC: Part 8, Testing Ajax and JSON

This is Part 8 in a series on unit testing MVC. Part 1 and an index to all posts in this series is here.

Just when you think you’ve done a good job with your application, good unit tests, users are happy, they bring you a change. In our case, the change calls for adding a country field to the Customer Create form. When the user picks the country, the State/Province field should populate with the states or provinces from that country. This will require making an AJAX call to the controller to get the list of states then returning that data via JSON.

We’ll need to create a Countries table and add a Country column to the States table. Then modify the State entity and add a Country Entity and supporting Repository, etc. Don’t forget to add the binding for Ninject and change the CustomerController constructor to accept the mocked Country table. You’ll need to change the tests to handle it too. Oh yes, a Country dropdown in Create.cshtml is needed too. I’ll be right here while you do all that.

Now that you made these changes we need to add a method to the CustomerController to return the JSON data.

   1:  public ActionResult GetStateValues(int countryId)
   2:  {
   3:      List<State> states = stateRepository.States
   4:  .Where(s => s.CountryId == countryId)
   5:  .OrderBy(s => s.Name).ToList();
   6:      var fs = from s in states
   7:                  select new
   8:                      {
   9:                          Code = s.Code,
  10:                          Name = s.Name
  11:                      };
  12:      JsonResult retVal = new JsonResult();
  13:      retVal.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
  14:      retVal.Data = fs.ToList();
  15:      return retVal;

 

We also need to add the javascript to the Customer Create.cshtml file to make the call

   1:  <script>
   2:      $(document).ready(function () {
   3:          $('#CountryId').change(function () {
   4:              $('#StateCode').html('');
   5:              $.getJSON('@Url.Action("GetStateValues")',
   6:  { countryId: $('#CountryId').val() }, function (data) {
   7:                  var items = "";
   8:                  $.each(data, function (i, item) {
   9:                      $("#StateCode").append('<option value="'
  10:  + item.Code + '">' +  item.Name + '</option>') ;
  11:                  });
  12:              });
  13:          });
  14:      });
  15:  </script>

Now compile and run the code. When you select a country, the javascript function is called. That function passes the selected country Id to the C# code in the controller. The states for that country are retrieved from the database and put into a JSON object, then return back to the page. The javascript code then loads the new items into the dropdown.

And finally, we’re at the test.. But it isn’t easy because the JSON result contains an anonymous type. We simply can’t call ToString(). In fact, if you do call result.Data.ToString(), the result will be System.Collections.Generic.List`1[<>f__AnonymousType4`2[System.String,System.String]]

Instead, we have to do what the .Net framework would do, serialize it. First, the UnitTests project needs a reference to the System.Web.Extensions assembly. Then add a using statement to System.Web.Script.Serialization.

   1:  [Test]
   2:  public void GetStateValues_Returns_ProperValues()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:      Mock<ICountryRepository> countryMock = new Mock<ICountryRepository>();
   8:  
   9:      stateMock.Setup(m => m.States).Returns(new State[]
  10:          {
  11:              new State {Id = 1, Code = "UT", Name = "Utah", CountryId = 2},
  12:              new State {Id = 1, Code = "CA", Name = "California", CountryId = 2},
  13:              new State {Id = 1, Code = "NY", Name = "New York", CountryId = 2},
  14:              new State {Id = 1, Code = "BC", Name = "British Colombia", CountryId = 1}
  15:          }.AsQueryable());
  16:  
  17:      CustomerController controller = new CustomerController(mock.Object,
  18:  stateMock.Object, countryMock.Object);
  19:  
  20:      // Act
  21:      JsonResult result = controller.GetStateValues(2) as JsonResult;
  22:      JavaScriptSerializer serializer = new JavaScriptSerializer();
  23:      string actual = serializer.Serialize(result.Data);
  24:  
  25:      // Assert
  26:      Assert.AreEqual(@"[{""Code"":""CA"",""Name"":""California""},
  27:  {""Code"":""NY"",""Name"":""New York""},
  28:  {""Code"":""UT"",""Name"":""Utah""}]", actual);
  29:  }

 

Line 21 gets the actual JsonResult from the controller. We pass a parameter of 2 to get the states in country 2. Line 22 instantiates the Serialize and then the result data is serialized in line 23. Lines 26-28 compare the expected data with what actually gets returned.

I have one more post to make in this series. In that I’ll summarize everything we’ve learned and address some nagging questions that you may have, some of what have been asked in the comments or direct emails to me.

Source: CraigBerntson

Unit Testing ASP.Net: Part 7, Testing Http Status Codes

This is Part 7 in a series on unit testing MVC. Part 1 and an index to all posts in this series is here.

In Part 6 if this series, I showed you how to handle two return types from the same method. I’ll continue that line with another method that returns multiple values. Here’ is the Delete method from the CustomerController.

   1:  public ActionResult Delete(int id = 0)
   2:  {
   3:      Customer customer = 
   4:          customerRepository.Customers.FirstOrDefault(c => c.Id == id);
   5:      if (customer == null)
   6:      {
   7:          return HttpNotFound();
   8:      }
   9:      return View(customer);
  10:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

You know how to handle the return View(customer), but what about HttpNotFound()? This return error causes the browser to display a 404 error. While it may be better to display an appropriate message, this is how the default scaffolding code is generated and there may be times you want to cause a 404. So, let’s see how to handle this in a unit test.

   1:  [Test]
   2:  public void Delete_Invalid_Customer_Returns_Http_404()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:   
   8:      CustomerController controller = new CustomerController(mock.Object, 
   9:  stateMock.Object);
  10:      CustomerCreateEditViewModel viewModel = 
  11:  new CustomerCreateEditViewModel();
  12:              
  13:      // Act
  14:      var actual = controller.Delete(27) as HttpNotFoundResult;
  15:   
  16:      // Assert
  17:      Assert.AreEqual(404, actual.StatusCode);
  18:  }
 
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Line 14 casts the return value to HttpNotFoundResult then in line 17 you Assert that the StatusCode value is 404. That’s it.

At this point, you should be able to write unit tests for all the methods in all three controllers in our example. But just as you get it done, you get a new requirement to add the country to the Customer Create and Edit pages. The user will first pick a country then the State/Province drop down will populate for the select country. This means you need to add a unit test to accept the Ajax call and test for a JSON response. I’ll show you how that’s done in Part 8.

Source: CraigBerntson

ASP.Net MVC Unit Testing: Part 6, The [HttpPost] Method

This is Part 6 in a series on unit testing MVC. Part 1 and an index to all posts in this series is here.

In the previous post in this series, I showed you how to get test SelectList objects. We replaced the model with a viewmodel and passed that to the View. However, we didn’t deal with actually saving the data. I also detoured from unit testing a bit to show an easy way to map a model to a view model. Now it’s time to get back to our topic and learn how to test is a method that has multiple return points. In our sample application, we’re going to test the [HttpPost] Create method.

   1:  [HttpPost]
   2:  [ValidateAntiForgeryToken]
   3:  public ActionResult Create(CustomerCreateEditViewModel viewModel)
   4:  {
   5:      if (ModelState.IsValid)
   6:      {
   7:          Customer customer = AutoMapper.Mapper.Map<CustomerCreateEditViewModel,
   8:  Customer>(viewModel);
   9:          customer = customerRepository.Save(customer);
  10:          return RedirectToAction("Index");
  11:      }
  12:  
  13:      return View(viewModel);
  14:  }

Let’s deal with the first return on line 10. In order to get to that return, ModelState.IsValid must be ture. But how do we ensure this? We’ll need to add some validation to the ViewModel. To keep it simple, I’ll just require a FirstName and LastName. Here’s the changed code snippet.

   1:  [Required]
   2:  [DisplayName("First name")]
   3:  public string FirstName { get; set; }
   4:  
   5:  [Required]
   6:  [DisplayName("Last name")]
   7:  public string LastName { get; set; }

 

Now we need to write a test. In an earlier post in this series, I changed the return value of the controller method from ActionResult to ViewResult. We can’t do that here because if the ViewState is Valid, it returns a RedirectToAction, not a View. So, we need to ensure that we’re getting a RedirectToAction. That’s our first test.

   1:  [Test]
   2:  public void Create_ViewState_Is_Valid_Returns_RedirectToRouteResult()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:  
   8:      CustomerController controller = new CustomerController(mock.Object,
   9:  stateMock.Object);
  10:      CustomerCreateEditViewModel viewModel =
  11:  new CustomerCreateEditViewModel();
  12:      viewModel.FirstName = "Fred";
  13:      viewModel.LastName = "Flintstone";
  14:      AutoMapper.Mapper.Reset();
  15:      AutoMapper.Mapper.CreateMap<CustomerCreateEditViewModel,
  16:  Customer>();
  17:  
  18:      // Act
  19:      var actual = controller.Create(viewModel);
  20:  
  21:      // Assert
  22:      Assert.IsInstanceOf<RedirectToRouteResult>(actual);
  23:  }



 

In lines 10-13 we setup the ViewModel so that it will be valid. Lines 14-16 setup the mapping needed so that AutoMapper will work. We then call the Create method of the controller and in line 19 assert the return value os of the proper type.

Next we need to verify that the route value that gets returned is correct. The Create method returns to the Index action so that’s what we need to test for.

   1:  [Test]
   2:  public void Create_ViewState_Is_Valid_Contains_Correct_Action()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:  
   8:      CustomerController controller = new CustomerController(mock.Object,
   9:  stateMock.Object);
  10:      CustomerCreateEditViewModel viewModel =
  11:  new CustomerCreateEditViewModel();
  12:      viewModel.FirstName = "Fred";
  13:      viewModel.LastName = "Flintstone";
  14:      AutoMapper.Mapper.Reset();
  15:      AutoMapper.Mapper.CreateMap<CustomerCreateEditViewModel,
  16:  Customer>();
  17:  
  18:      // Act
  19:      var actual = controller.Create(viewModel) as RedirectToRouteResult;
  20:  
  21:      // Assert
  22:      Assert.AreEqual("Index", actual.RouteValues["action"]);
  23:  }


 

This test is similar to the previous one except that we cast the return value to RedirectToRouteResult so that we can interrogate it further. Line 19 asserts that the action is Index. Once you get green on both tests, it’s time to handle the condition that the ViewState is false.

First, change the return statement of the [HttpPost] Create method so it contains the actual View we want. Otherwise, the ViewName property is empty.

   1:  return View("Create", viewModel);

 

For our tests, we can test two things. The first is that we get a ViewResult (which is the View).

   1:  [Test]
   2:  public void Create_ViewState_Is_Invalid_Returns_ViewResult()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:  
   8:      CustomerController controller = new CustomerController(mock.Object,
   9:  stateMock.Object);
  10:      CustomerCreateEditViewModel viewModel =
  11:  new CustomerCreateEditViewModel();
  12:      controller.ModelState.AddModelError("FirstName", "First name is required");
  13:  
  14:      // Act
  15:      var actual = controller.Create(viewModel) as ViewResult;
  16:  
  17:      // Assert
  18:      Assert.IsInstanceOf<ViewResult>(actual);
  19:  }

 

In line 12, we set an error condition on the ModelState so it won’t pass. The Assert in line 18 verifies we get a ViewResult.

Now for the second test, we need to make sure we get the Create View.

   1:  [Test]
   2:  public void Create_ViewState_Is_Invalid_Returns_Correct_View()
   3:  {
   4:      // Arrange
   5:      Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
   6:      Mock<IStateRepository> stateMock = new Mock<IStateRepository>();
   7:  
   8:      CustomerController controller = new CustomerController(mock.Object,
   9:  stateMock.Object);
  10:      CustomerCreateEditViewModel viewModel =
  11:  new CustomerCreateEditViewModel();
  12:      controller.ModelState.AddModelError("FirstName", "First name is required");
  13:  
  14:      // Act
  15:      var actual = controller.Create(viewModel) as ViewResult;
  16:  
  17:      // Assert
  18:      Assert.AreEqual("Create", actual.ViewName);
  19:  }

Really, the only difference between these last two tests is the Assert.

That wraps up testing the Create method. It should be easy to write tests for the Edit methods as they are the same as Create. Now we turn our attention to the Delete method.

   1:  public ActionResult Delete(int id = 0)
   2:  {
   3:      Customer customer =
   4:          customerRepository.Customers.FirstOrDefault(c => c.Id == id);
   5:      if (customer == null)
   6:      {
   7:          return HttpNotFound();
   8:      }
   9:      return View(customer);
  10:  }

 

Note the if statement on lines 5-8. If the requested Customer row isn’t found, the method returns HttpNotFound which results in a 404 error page in the browser. How do we test for this? That, is the topic of the next part in this series.

Source: CraigBerntson

Newer posts »

© 2017 Software Gardening

Theme by Anders NorenUp ↑