I've recently switched from using TFS to using Git as my Version Control System of choice. Some folks have been having issues making the transition so I put together a guide to get them through the process and I wanted to share it here for others.
The first thing I want to do is put a disclaimer out that I stole the name of this post from a session at Desert Code Camp last year. Sorry, dude who presented it. It was catchy.
I may edit this post in the future with some shortcuts and stuff, but for now here's a link to the slideshow I put together to present at work: https://docs.google.com/presentation/d/1KOc1M4KlXgzvdoRhjkcaZ8FeSOoN0z1RVnI8odSZo_0/edit?usp=sharing
Resolutions to software engineering problems that I couldn't find anywhere else on the Internet. This is mostly here so I can find all my past solutions in one place.
Sunday, March 19, 2017
Saturday, February 11, 2017
Testing Resolves in Jasmine
I've come across this issue before and I came up with a different answer (I think), but I can't remember that answer and I can't find it here. So today I'm posting my new answer so at least I have this one for next time.
I'm using Angular UI Bootstrap's modal control to... open a modal. I suppose that's kind of obvious. Anyway, when you open a modal you can pass functions in that get resolved in the controller. I'm not going to explain that in great detail here.
My problem was testing those resolves in my modal instance controller. The resolves look something like this:
Since they're functions, UI Bootstrap is going to handle resolving them (get it?) to their returned values. So when the controller loads, student will be an empty object and title will be that text. When I test the modal instance controller I'll just be sure to inject those resolved values instead of functions. It looks like this:
Now in my tests I can use those values the same way they'll be used in the actual code. I answered a question on Stack Overflow about this topic a while back, but I can't recall what code I was looking at that prompted me to go looking for an answer that lead me to that question that I was able to answer. Anyway, here's my answer on SO: http://stackoverflow.com/questions/37023953/unit-testing-ui-router-with-resolve/37075491#37075491
I'm using Angular UI Bootstrap's modal control to... open a modal. I suppose that's kind of obvious. Anyway, when you open a modal you can pass functions in that get resolved in the controller. I'm not going to explain that in great detail here.
My problem was testing those resolves in my modal instance controller. The resolves look something like this:
resolve: {
student: function() {
return {};
},
title: function() {
return 'Add a Student';
}
}
Since they're functions, UI Bootstrap is going to handle resolving them (get it?) to their returned values. So when the controller loads, student will be an empty object and title will be that text. When I test the modal instance controller I'll just be sure to inject those resolved values instead of functions. It looks like this:
beforeEach(inject(function(_$rootScope_, _$controller_) {
scope = _$rootScope_.$new();
_$controller_('studentController', { $scope: scope, title: 'Add a Student', meal: {} });
}));
Now in my tests I can use those values the same way they'll be used in the actual code. I answered a question on Stack Overflow about this topic a while back, but I can't recall what code I was looking at that prompted me to go looking for an answer that lead me to that question that I was able to answer. Anyway, here's my answer on SO: http://stackoverflow.com/questions/37023953/unit-testing-ui-router-with-resolve/37075491#37075491
Tuesday, December 20, 2016
Testing "this" with Jasmine
I had cause to test a function that references this in JavaScript and, although it ended up being easy, it took some figuring to get there. Rather than have to figure it all out again (and maybe to save someone else some trouble, too) I'm putting my solutions here (yes, there are two solutions).
Here is the function I needed to test:
The first - and easiest - solution is to set whatever you need on scope. In Angular, when this is referenced, it's referring to scope so in my case I was using this.dataSource.data() so I was able to just set an object directly on scope called dataSource that had a data function.
The second - and in my opinion more correct - solution is to invoke the function using call and pass whatever you want this to be as your first parameter.
They're pretty similar, but I prefer using call because it should work outside Angular as well.
Mozilla has a pretty sweet explanation of this and how to use it in case you want more detailed information.
Here is the function I needed to test:
$scope.dataBound = function(e) {
var data = this.dataSource.data();
for (var i = data.length; --i >= 0;) {
if (!data[i].IsBundle) {
var row = $('#grid')
.data('kendoGrid')
.tbody.find('tr[data-uid="' + data[i].uid + '"]');
$(row).find('td.k-hierarchy-cell .k-icon').removeClass();
}
}
};
The first - and easiest - solution is to set whatever you need on scope. In Angular, when this is referenced, it's referring to scope so in my case I was using this.dataSource.data() so I was able to just set an object directly on scope called dataSource that had a data function.
it('should set this on scope', function() {
// arrange
scope.dataSource = {
data: function() {
return [];
}
};
spyOn(scope.dataSource, 'data').and.callThrough();
// act
scope.dataBound();
// assert
expect(scope.dataSource.data).toHaveBeenCalledTimes(1);
});
The second - and in my opinion more correct - solution is to invoke the function using call and pass whatever you want this to be as your first parameter.
it('should set pass this using call', function() {
// arrange
var thisToSet = {
dataSource: {
data: function() {
return [];
}
}
};
spyOn(thisToSet.dataSource, 'data').and.callThrough();
// act
scope.dataBound.call(thisToSet);
// assert
expect(thisToSet.dataSource.data).toHaveBeenCalledTimes(1);
});
They're pretty similar, but I prefer using call because it should work outside Angular as well.
Mozilla has a pretty sweet explanation of this and how to use it in case you want more detailed information.
Kendo UI Directives
Below is a list of directives found in the Kendo UI module. I was trying to figure out how to set just the data of a data source on a grid and couldn't find a list. I came across a question on SO asking for a list, but there was no answer. I found another question on SO on how to list out the registered items in an Angular module, ran that against the kendo.directives module and voila!
This list is from the 2016.3.1118 release (please note that this is just a list of directives so if you're looking for something else you'll have to modify the code and get it yourself).
The code I used to generate the list:
The list:
2kendoAlert
2kendoAttribution
2kendoBarcode
2kendoBreadcrumbs
2kendoButton
2kendoCalendar
2kendoChart
2kendoConfirm
2kendoDiagram
2kendoDialog
2kendoDraggable
2kendoEditable
2kendoEditor
2kendoGantt
2kendoGrid
2kendoGroupable
2kendoMap
2kendoMenu
2kendoNavigator
2kendoNotification
2kendoPager
2kendoPopup
2kendoPrompt
2kendoReorderable
2kendoResizable
2kendoScheduler
2kendoSelectable
2kendoSlider
2kendoSortable
2kendoSparkline
2kendoSplitter
2kendoSpreadsheet
2kendoSurface
2kendoTooltip
2kendoTouch
2kendoUpload
2kendoValidator
2kendoWindow
kActionsheetContext
kAlign
kAllDayEventTemplate
kAltRowTemplate
kAltTemplate
kColumnHeaderTemplate
kDataCellTemplate
kDateHeaderTemplate
kDetailTemplate
kEditTemplate
kEmptyTemplate
kendoAutoComplete
kendoColorPalette
kendoColorPicker
kendoColumnMenu
kendoColumnSorter
kendoComboBox
kendoContextMenu
kendoDatePicker
kendoDateTimePicker
kendoDropDownList
kendoDropTarget
kendoDropTargetArea
kendoFileBrowser
kendoFilterCell
kendoFilterMenu
kendoFilterMultiCheck
kendoFlatColorPicker
kendoImageBrowser
kendoLinearGauge
kendoListView
kendoMaskedTextBox
kendoMediaPlayer
kendoMobileActionSheet
kendoMobileApplication
kendoMobileBackButton
kendoMobileButton
kendoMobileButtonGroup
kendoMobileCollapsible
kendoMobileDetailButton
kendoMobileDrawer
kendoMobileFooter
kendoMobileHeader
kendoMobileLayout
kendoMobileListView
kendoMobileLoader
kendoMobileModalView
kendoMobileNavBar
kendoMobilePane
kendoMobilePopOver
kendoMobilePopup
kendoMobileRecurrenceEditor
kendoMobileScroller
kendoMobileScrollView
kendoMobileScrollViewPage
kendoMobileShim
kendoMobileSplitView
kendoMobileSwitch
kendoMobileTabStrip
kendoMobileTimezoneEditor
kendoMobileView
kendoMultiSelect
kendoNumericTextBox
kendoPanelBar
kendoPivotConfigurator
kendoPivotFieldMenu
kendoPivotGrid
kendoProgressBar
kendoQRCode
kendoRadialGauge
kendoRangeSlider
kendoRecurrenceEditor
kendoResponsivePanel
kendoSearchBox
kendoSelectBox
kendoStaticList
kendoStockChart
kendoTabStrip
kendoTimePicker
kendoTimezoneEditor
kendoToolBar
kendoTreeList
kendoTreeMap
kendoTreeView
kendoViewTitle
kendoVirtualList
kendoVirtualScrollable
kendoZoomControl
kErrorTemplate
kEventTemplate
kHeaderTemplate
kIcon
kLinkTemplate
kMajorTimeHeaderTemplate
kMinorTimeHeaderTemplate
kRel
kRowHeaderTemplate
kRowTemplate
kSelectTemplate
kTemplate
kTransition
This list is from the 2016.3.1118 release (please note that this is just a list of directives so if you're looking for something else you'll have to modify the code and get it yourself).
The code I used to generate the list:
1: angular.module('kendo.directives')['_invokeQueue'].forEach(function(value) {
2: if (value[1] === 'directive') {
3: console.log(value[2][0]);
4: }
5: });
The list:
2kendoAlert
2kendoAttribution
2kendoBarcode
2kendoBreadcrumbs
2kendoButton
2kendoCalendar
2kendoChart
2kendoConfirm
2kendoDiagram
2kendoDialog
2kendoDraggable
2kendoEditable
2kendoEditor
2kendoGantt
2kendoGrid
2kendoGroupable
2kendoMap
2kendoMenu
2kendoNavigator
2kendoNotification
2kendoPager
2kendoPopup
2kendoPrompt
2kendoReorderable
2kendoResizable
2kendoScheduler
2kendoSelectable
2kendoSlider
2kendoSortable
2kendoSparkline
2kendoSplitter
2kendoSpreadsheet
2kendoSurface
2kendoTooltip
2kendoTouch
2kendoUpload
2kendoValidator
2kendoWindow
kActionsheetContext
kAlign
kAllDayEventTemplate
kAltRowTemplate
kAltTemplate
kColumnHeaderTemplate
kDataCellTemplate
kDateHeaderTemplate
kDetailTemplate
kEditTemplate
kEmptyTemplate
kendoAutoComplete
kendoColorPalette
kendoColorPicker
kendoColumnMenu
kendoColumnSorter
kendoComboBox
kendoContextMenu
kendoDatePicker
kendoDateTimePicker
kendoDropDownList
kendoDropTarget
kendoDropTargetArea
kendoFileBrowser
kendoFilterCell
kendoFilterMenu
kendoFilterMultiCheck
kendoFlatColorPicker
kendoImageBrowser
kendoLinearGauge
kendoListView
kendoMaskedTextBox
kendoMediaPlayer
kendoMobileActionSheet
kendoMobileApplication
kendoMobileBackButton
kendoMobileButton
kendoMobileButtonGroup
kendoMobileCollapsible
kendoMobileDetailButton
kendoMobileDrawer
kendoMobileFooter
kendoMobileHeader
kendoMobileLayout
kendoMobileListView
kendoMobileLoader
kendoMobileModalView
kendoMobileNavBar
kendoMobilePane
kendoMobilePopOver
kendoMobilePopup
kendoMobileRecurrenceEditor
kendoMobileScroller
kendoMobileScrollView
kendoMobileScrollViewPage
kendoMobileShim
kendoMobileSplitView
kendoMobileSwitch
kendoMobileTabStrip
kendoMobileTimezoneEditor
kendoMobileView
kendoMultiSelect
kendoNumericTextBox
kendoPanelBar
kendoPivotConfigurator
kendoPivotFieldMenu
kendoPivotGrid
kendoProgressBar
kendoQRCode
kendoRadialGauge
kendoRangeSlider
kendoRecurrenceEditor
kendoResponsivePanel
kendoSearchBox
kendoSelectBox
kendoStaticList
kendoStockChart
kendoTabStrip
kendoTimePicker
kendoTimezoneEditor
kendoToolBar
kendoTreeList
kendoTreeMap
kendoTreeView
kendoViewTitle
kendoVirtualList
kendoVirtualScrollable
kendoZoomControl
kErrorTemplate
kEventTemplate
kHeaderTemplate
kIcon
kLinkTemplate
kMajorTimeHeaderTemplate
kMinorTimeHeaderTemplate
kRel
kRowHeaderTemplate
kRowTemplate
kSelectTemplate
kTemplate
kTransition
Thursday, December 1, 2016
Testing a Request in an ApiController
I recently came across a situation where I needed to test an action method on an ApiController to make sure the correct response was returned to the user based on the request. In this particular case I was testing the ability to upload a file to an API and I needed to return a 400 (Bad Request) error if the content type of the request was not right. I knew the code was working (I know, it wasn't TDD, but sometimes you have to roll with the punches), but I was having a hard time testing it. To make things worse I couldn't use shims or fakes because the build server kept blowing up on them. Fortunately, I came across a couple of really helpful blogs that pointed me in the right direction.
First, Shiju Varghese's blog on writing unit tests for an ApiController. Next I used William Hallat's blog on testing a file upload to finish things off.
What I ended up with is pretty neat and easy to use, customized to meet my needs. As usual, I'm posting it here so I don't have to redo the work next time.
The first key to making this work is declaring the controller. Let's just say that our controller has a single object injected, an ILogger (a fairly common practice). Instead of just doing this:
We want to do this:
UPDATE: We actually also want to include an HttpConfiguration to prevent another error I was getting later:
This declares that the request passed to the controller will actually be specified to contain content and a method (POST in this case). Now that we have that, our tests won't fail with the awful (and unhelpful) "Object reference not set to an instance of an object" error you might be seeing.
In this case we've specified that the content will be a string, but we haven't specified any actual content. But as I said before I needed to test whether the content was a file that had been uploaded, then also take certain actions based on that file. To do that I actually needed to fake a file upload in the request itself.
A little bit of setup (this happens before each test run not each test):
The test:
The method called by the test:
And finally, the controller action method:
This solved my problem and enabled me to test my action method on my controller.
First, Shiju Varghese's blog on writing unit tests for an ApiController. Next I used William Hallat's blog on testing a file upload to finish things off.
What I ended up with is pretty neat and easy to use, customized to meet my needs. As usual, I'm posting it here so I don't have to redo the work next time.
The first key to making this work is declaring the controller. Let's just say that our controller has a single object injected, an ILogger (a fairly common practice). Instead of just doing this:
var controller = new ExampleController(_moqLogger.Object);
We want to do this:
1: var controller = new ExampleController(_moqLogger.Object)
2: {
3: Request = new HttpRequestMessage
4: {
5: Content = new ObjectContent(typeof(string), null, new JsonMediaTypeFormatter()),
6: Method = HttpMethod.Post
7: }
8: };
UPDATE: We actually also want to include an HttpConfiguration to prevent another error I was getting later:
1: var request = new HttpRequestMessage
2: {
3: Content = new ObjectContent(typeof(string), null, new JsonMediaTypeFormatter()),
4: Method = HttpMethod.Post
5: };
6: request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
7: var controller = new ExampleController(_moqLogger.Object)
8: {
9: Request = request
8: };
This declares that the request passed to the controller will actually be specified to contain content and a method (POST in this case). Now that we have that, our tests won't fail with the awful (and unhelpful) "Object reference not set to an instance of an object" error you might be seeing.
In this case we've specified that the content will be a string, but we haven't specified any actual content. But as I said before I needed to test whether the content was a file that had been uploaded, then also take certain actions based on that file. To do that I actually needed to fake a file upload in the request itself.
A little bit of setup (this happens before each test run not each test):
1: [TestFixtureSetUp]
2: public void SetUpFixture()
3: {
4: using (var outFile = new StreamWriter(_testFile))
5: {
6: outFile.WriteLine("some test data");
7: }
8: }
The test:
1: [Test]
2: public void DoSomethingShouldReturnAnOkResult()
3: {
4: // arrange
5: var multipartContent = BuildFormDataContent();
6: multipartContent.Add(new StringContent("some value"), "someKey");
7:
8: var controller = new ExampleController(_moqLogger.Object)
9: {
10: Request = new HttpRequestMessage
11: {
12: Content = multipartContent,
13: Method = HttpMethod.Post
14: }
15: };
16:
17: // act
18: var response = controller.DoSomething();
19:
20: // assert
21: Assert.IsInstanceOf<OkResult>(response.Result);
22: }
The method called by the test:
1: private string _testFile = "test.file";
2:
3: private MultipartFormDataContent BuildFormDataContent()
4: {
5: var multipartContent = new MultipartFormDataContent("boundary=---011000010111000001101001");
6:
7: var fileStream = new FileStream(_testFile, FileMode.Open, FileAccess.Read);
8: var streamContent = new StreamContent(fileStream);
9: streamContent.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
10:
11: multipartContent.Add(streamContent, "TheFormDataKeyForTheFile", _testFile);
12:
13: return multipartContent;
14: }
And finally, the controller action method:
1: [HttpPost]
2: public async Task<IHttpActionResult> DoSomething()
3: {
4: if (!Request.Content.IsMimeMultipartContent("form-data"))
5: {
6: _logger.Information(() => "Unsupported media type");
7: return BadRequest("Unsupported media type");
8: }
9:
10: try
11: {
12: var root = @"C:\";
13: var provider = new MultipartFormDataStreamProvider(root);
14: await Request.Content.ReadAsMultipartAsync(provider);
15:
16: var someValue = provider.FormData.GetValues("someKey").FirstOrDefault();
17:
18: foreach (var file in provider.FileData)
19: {
20: var fileInfo = new FileInfo(file.LocalFileName);
21: // do something with the file here that returns a boolean
22: if(someOtherMethod()){
23: return Ok();
24: }
25:
26: return InternalServerError(new Exception("An error was encountered while processing the request"));
27: }
28:
29: return Ok();
30: }
31: catch (Exception ex)
32: {
33: return InternalServerError(ex);
34: }
35: }
This solved my problem and enabled me to test my action method on my controller.
Friday, November 18, 2016
Testing Exception Messages with MS Test
I usually use NUnit to do my C# unit tests, but when I need to use the Microsoft Fakes framework I have to use the built-in (to Visual Studio) MS Test framework. This is because Fakes requires instrumentation ability that NUnit just doesn't have. It also means I can't use the Resharper test runner like I normally do. Neither of those changes is usually a problem, but today I found out that testing an exception message in MS Test is actually a bit tricky.
You can use the
You use it just like you used
You can use the
[ExpectedException]
attribute around a test to indicate to MS Test that you expect that test to throw an exception. However, even though there is an overload for that attribute that accepts a message, it's not actually used to test whether the thrown exception has the message you specify in the attribute. So
[ExpectedException(typeof(ArgumentNullException), "A name is required")]
doesn't actually check whether the message on the exception is
"A name is required"
. Instead, if that test fails (which would happen if an exception wasn't thrown since you're expecting that one will be thrown) the text that will appear in Test Explorer is
"A name is required"
.
The good news is that there's an easy way around this. The bad news is you still have to create your own attribute to do it. It's not complicated. h/t to BlackjacketMack on SO for posting his solution here.1: public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
2: {
3: public Type ExceptionType { get; set; }
4:
5: public string ExpectedMessage { get; set; }
6:
7: public ExpectedExceptionWithMessageAttribute(Type exceptionType)
8: {
9: ExceptionType = exceptionType;
10: }
11:
12: public ExpectedExceptionWithMessageAttribute(Type exceptionType, string message)
13: {
14: ExceptionType = exceptionType;
15: ExpectedMessage = message;
16: }
17:
18: protected override void Verify(Exception exception)
19: {
20: if (exception.GetType() != ExceptionType)
21: {
22: NUnit.Framework.Assert.Fail(
23: "ExpectedExceptionWithMessageAttribute failed. Expected exception type: {0}. Actual exception type: {1}. Exception message: {2}",
24: ExceptionType.FullName, exception.GetType().FullName, exception.Message);
25: }
26:
27: var actualMessage = exception.Message.Trim();
28:
29: if (ExpectedMessage != null)
30: {
31: Assert.AreEqual(ExpectedMessage, actualMessage);
32: }
33: }
34: }
You use it just like you used
[ExpectedException]
earlier.
[ExpectedExceptionWithMessage(typeof(ArgumentNullException), "A name is required")]
More Fun with Shims
I'm finally back to doing some server side code (as opposed to the client stuff I've been working exclusively with for several months) and I found myself in need of some unit tests. It's been a long time since I used a shim from Microsoft's Fakes framework so I had to poke and prod it for a while to work and I don't want to forget what I did. Here goes:
In this particular example I was working with the WSUS API provided by Microsoft to interact with WSUS. I specifically was trying to save a new signing certificate, but I obviously didn't want to actually do that on a WSUS server. The solution was to use shims and stubs this time.
I broke out a bunch of the stub creation stuff so I could reuse it across multiple tests. That's what the PrepareIUpdateServerStub method is for. That's also why I have the global variables _fileNameParameter and _passwordParameter. The method I was testing is essentially a pass-through to the WSUS API that we reuse in multiple applications so the method itself was fairly straightforward (check if a file and password were passed, then pass them on to WSUS).
Like I said at the beginning, working with Shims, Fakes, and Stubs is always a challenge for me so hopefully this documentation will help me next time I need to do it.
In this particular example I was working with the WSUS API provided by Microsoft to interact with WSUS. I specifically was trying to save a new signing certificate, but I obviously didn't want to actually do that on a WSUS server. The solution was to use shims and stubs this time.
1: private string _fileNameParameter = "empty";
2: private SecureString _passwordParameter = new SecureString();
1: private StubIUpdateServer PrepareIUpdateServerStub()
2: {
3: FakesDelegates.Action<string, SecureString> setSigningCertificateAction = (fileName, password) =>
4: {
5: _fileNameParameter = fileName;
6: _passwordParameter = password;
7: };
8:
9: var iUpdateServerConfiguration = new StubIUpdateServerConfiguration
10: {
11: SetSigningCertificateStringSecureString = setSigningCertificateAction
12: };
13:
14: var iUpdateServerStub = new StubIUpdateServer
15: {
16: GetConfiguration = () => iUpdateServerConfiguration
17: };
18:
19: return iUpdateServerStub;
20: }
1: [TestMethod]
2: public void SetSigningCertificateShouldPassParametersToWsusApiAndReturnTrue()
3: {
4: using (ShimsContext.Create())
5: {
6: // arrange
7: const string expectedFileName = "fileName";
8: const string expectedPasswordString = "password";
9: var expectedPassword = new SecureString();
10: foreach (var c in expectedPasswordString)
11: {
12: expectedPassword.AppendChar(c);
13: }
14:
15: ShimAdminProxy.GetUpdateServerStringBooleanInt32 = (name, isSsl, port) => PrepareIUpdateServerStub();
16:
17: var wsusRepository = new WsusRepository();
18:
19: // act
20: var result = wsusRepository.SetSigningCertificate(expectedFileName, expectedPassword);
21:
22: // assert
23: Assert.AreEqual(expectedFileName, _fileNameParameter);
24: Assert.AreEqual(expectedPassword.ToString(), _passwordParameter.ToString());
25: Assert.IsTrue(result);
26: }
27: }
I broke out a bunch of the stub creation stuff so I could reuse it across multiple tests. That's what the PrepareIUpdateServerStub method is for. That's also why I have the global variables _fileNameParameter and _passwordParameter. The method I was testing is essentially a pass-through to the WSUS API that we reuse in multiple applications so the method itself was fairly straightforward (check if a file and password were passed, then pass them on to WSUS).
Like I said at the beginning, working with Shims, Fakes, and Stubs is always a challenge for me so hopefully this documentation will help me next time I need to do it.
Subscribe to:
Posts (Atom)