SQLite in ASP.NET Core WITHOUT Entity Framework

Try and search for ASP.NET Core and SQLite and you’ll get a dozen guides to using it with Entity Framework.

First of all, we’ll need an ASP.NET Core website and install the Nuget packages Microsoft.Data.Sqlite and System.Data.Sqlite.

I prefer to use Dapper for my database access (hence not wanting to use Entity Framework), so go ahead and install Dapper too.

Opening any connection in SQLite by default automatically creates the database file. Run this code:

var connectionStringBuilder = new SqliteConnectionStringBuilder();
connectionStringBuilder.DataSource = "MyNewDatabase.db";
using (var connection = new SqliteConnection(connectionStringBuilder.ConnectionString))
{     connection.Open();     var result = connection.Query<int>("SELECT @number;", new { number = 789 });
}

And you’ll see in the /bin/debug folder there is a new (empty) file called MyNewDatabase.db. Setting a breakpoint and inspecting the result variable will also reveal that the database is responding nicely to queries. It should have a list of a single item, and that item is the number 789.

Running basic queries for fun isn’t very exciting though. We need to be able to connect to the database, create tables and interrogate them. The way to do this with SQLite is through the command line. Since I’ve been playing with Linux, I loaded up Bash for Windows 10 and gave it a go.

To do it like that, run sudo apt-get install sqlite3 in your Bash shell to get the client application. Then navigate to the database file location (you can get to the main drives with cd /mnt/c, where c is your drive letter). Then hit sqlite3 MyNewDatabase.db, and you’re into command line SQL mode! All commands must be terminated with a semi-colon, but otherwise it’s easy to add tables, set them up, etc. I will be saving all the commands in a separate file so the scripts can be re-run if necessary, or if I choose to create a new database on the live environment and deploy to it separately.

A few hints from this site on using SQLite:

To list all tables, type .tables and to exit the command line type .quit.

New Year, New Host, New Blog

I mentioned at the start of the year, I’m hoping to get back into blogging a bit more this year. I had a pretty good run of posting once a fortnight, but it fell away as my commute got shorter and less convenient for typing.

I’ve moved my blog to Digital Ocean. The reason is partly cost-based, but also because I wanted to play around with SSL certificates for DreadBall Hub. My previous web host was eHosting, a UK based provider of Windows hosting. That was important as a .NET developer, until last year when .NET Core has brought my skills to Linux.

Anyway, I wanted an SSL certificate and could get a free one from Let’s Encrypt. I spoke to eHosting, and they said that I could absolutely install a third-party certificate like Let’s Encrypt, but I’d need a static IP address. That’d be £1 a month (+VAT). Well, that was still cheaper than the £50-100 for another provider’s certificate, so I thought it was worth the cost. Unfortunately, I couldn’t find the option to buy that add-on.

Their support staff were very helpful – the solution was to upgrade my subscription at an additional cost of £5 a month (+VAT), so that I could buy the £1.20 add-on for a static IP address. So that’s a total cost of £72 (+VAT) a year, to get a free SSL certificate.

Rather than spending an extra £80+ every year, I decided that with the Linux portability of .NET Core another option was open to me. Try out a Linux server (and Digital Ocean charge by the hour, so I’m not locked in too tightly) and see if I can do everything I want on there. Even with the collapse of the pound against the dollar, the hosting is cheaper than I was paying at eHosting with the downside of having to be the administrator.

The upside of course is that with free SSL certificates, this blog and DreadBall Hub are now encrypted. My mail is handled by another free domain-mail handler. I’m saving money, and I’m getting to learn new things about Linux and .NET Core – exciting new stuff! Onwards and upwards!

Radio Stars

Podcasts are fantastic. I don’t like media that isn’t on demand, like traditional television and radio. I don’t know why I let theatre off, maybe because it’s more of a conscious decision to consume theatre.

That doesn’t mean that I don’t like the content (although most of it is garbage) – I love DVDs and own a few television series on DVD so that I can watch it when it’s convenient (and pause it when the kids wake up), and I listen to a lot of podcasts. Since I started a new job in Cardiff and hence do a lot of commuting, I’ve been listening to even more – and here they are.

.NET Rocks

This is a good one to start with – it’s one I’m thinking of giving up. I started listening to it a few years ago as one of the first podcasts I picked up. It’s a technology podcast about .NET stuff, programming stuff and related fields. Unfortunately, it’s a pretty heavy schedule and puts out two shows a week of about an hour, and not all of the topics are relevant to me as it’s quite a broad range of subjects. They also seem to have quite a heavy bias towards Agile methodologies, and I’m not a fan of those yet. Although one episode did seem a little sceptical about them, so maybe they’re just playing up to whatever guest they have. I don’t think the value I get out of it is worth it.

On the other hand, it is good to put on in the background and mostly ignore when I am working from home – I’ll see how that goes.

The D6 Generation

The D6 Generation is a mammoth show about games – mostly board games, though they are familiar with (and less fanboyish than) tabletop wargames. There’s always a quiz, usually a guest, and the most in-depth reviews I’ve ever heard to give you an idea of playing a game. I’ve picked up a couple of suggestions for future additions to Games Night from this show, but so far not tested their reviews. I also love that they don’t blindly review things, they actually give negative opinions if they don’t like a game.

This is another one I listened to many years ago and dropped, because each episode is over 3 hours long and come out every 3-4 weeks. Now that I’m commuting over 5 hours a week, I have the time for this show again and I get an awful lot out of it.

Dan Carlin’s Hardcore History

I’ve only recently picked this one up but gone back through the archive as far as the RSS feed goes. This took me back as far as an episode on the Age of Exploration and the whole of the Death of the Roman Republic series. It’s a fantastic podcast, although each episode is a few hours long they only come out every couple of months and I still have the whole Wrath of the Khans series to get through to keep me going. I try and keep these episodes as a treat to myself for having finished listening to everything else on the list, else I would just blow through them all in no time at all.

Hanselminutes

I think this is the only podcast that I’ve been listening to since the very start. It’s another .NET technology podcast, but occasionally branches into other areas like organisational skills, diabetes and disability, fitness and hobbies, but Scott Hanselman is an excellent host and as it’s only a half-hour show it’s very easy to fit in to the daily commute and learn a little bit about a range of subjects.

I realised how long I had been listening to this show when I met up with some developer friends, mentioned a Hanselminutes show about something we were discussing, and when I went to the archives to find it for them found it had been over three years before!

Webcomics Weekly

Technically, this is another one that I’ve been listening to since I started listening to podcasts – it may even have been the first podcast I listened to. But it stopped being weekly, then it stopped being… then it came back for a few episodes and disappeared again. It’s still on the RSS reader if it ever updates again, but I’m not holding my breath.

Heelanhammer

This is the first Warhammer podcast I subscribed to, and I thought it was fantastic. Unfortunately it’s ceased recording now, but at least (unlike Webcomics Weekly) they officially announced their end. Ironically, it was after a week where they joked about finishing up the show.

While writing this, however, they have announced that after a nine month hiatus, they are coming back in the middle of March! Hooray!

Bad Dice

The second Warhammer podcast I started listening to, I almost quit this one immediately. The first episode I listened to had three guests, and one didn’t play Warhammer and was just being a snarky, rude and extremely annoying twerp. The following week, it was announced that he and another of the guests would be co-hosts going forward, and he was marginally less annoying.

I stuck it out, and over the past year Gareth has been getting better and better and made the podcast really enjoyable. He’s an excellent counterpoint to the tournament-heavy bent of the other hosts, asking simple questions and getting used to things slowly just like people who don’t play Warhammer at least once a week. I’m glad I didn’t quit on it back in the beginning.

Bad Dice Daily

This is a spin-off from the Bad Dice podcast (the clue is in the name) where the main host (Ben Curry) talks for 15-20 minutes each day on a different subject. I don’t sync episodes on my phone every day, so I normally end up with a few to listen to all at once. It’s an excellent show, short enough to not get annoying if the subject is dull (most tournament results or White Dwarf news, for me) but long enough to impart useful knowledge such as the “How to Paint Black” or “How to Paint White” episodes.

Mantic Podcast

I’ve become a big Mantic fan in the last year – their Kings of War ruleset is interesting and if I had more time to play, I’d love to give it a go, and I’ve mentioned Dreadball on this blog a few times already. They put out an infrequent podcast also hosted by Ben Curry and since most of these recently have been about Dreadball, I’ve been listening avidly.

Garagehammer

I picked this one up when Ben Curry of Bad Dice was a guest on it talking about Dark Elves (my favourite army), their tactics, and the rest. I added it to the regular subscription list and figured I’d see how I liked it – and I did! They are more hobby focussed than Bad Dice, and they’re not serial tournament champions. Since Heelanhammer finished, they’ve definitely filled a void that Bad Dice doesn’t quite fit. Some of their best and worst episodes are their playthrough battle reports – during a game, they take breaks to describe the turn. It might be just that sometimes I’m not paying complete attention to the podcast (something I make sure to do with shows like Hardcore Histories), but I can’t always visualise the game and lose the thread of things, and at that point I just want it to be over and skip to the next bit.

Radio 4 Friday Night Comedy and Comedy of the Week

When I used to drive to work on my own, I got used to listening to the radio. I eventually gravitated to Radio 4 because Radio 1 is not for me, Radio 2 was hit and miss with the DJs, and every other station has adverts and I can’t stand adverts. Jack FM is best of a bad bunch, but I found that at the same time every Wednesday evening there would be Steve Harley Come Up and See Me, and that was the nail in the repetitive playlist coffin. Then we removed the car radio but didn’t replace it so that was the end of the radio for me.

These podcasts are (usually) hilarious and give me something that amateur comedy podcasts don’t usually do and in a British accent. Listening to too many American accents can get irritating and most of my podcasts now (or at least the longest podcasts) are American.

LRRCast

This podcast is put out by the LoadingReadyRun team and has changed over the last year – they used to go into some detail on how their videos are made, but since this is now handled by the Loading Time video series, they’ve reduced that content. The Ask LRR section is a bit hit and miss – sometimes it’s really interesting and other times it’s “what Magic card would you be if you were the opposite gender”. After a long hiatus, they’ve also come back with a new format – regular LRRCast once a month, a Magic podcast once a month, and a games podcast once a month. This is nice, because if I don’t feel like listening to a bunch of Magic: The Gathering stuff (and why would I? I don’t play!) I can just skip it. Similarly, I’m just not into computer games as much as I used to be, so that one is skipped too.

Penn’s Sunday School

Penn Jillette, the noisy part of Penn & Teller, puts up a libertarian, atheist music-loving podcast.

This is another podcast I almost dropped – before I had a big catch-up a couple of weeks ago, it was always the one I passed over for other things. The big problem was an episode a fair while ago that just had so many adverts it bored me – especially since most of the adverts were for American berry supplies, American postage stuff, etc. It’s just not relevant or interesting. I usually catch up on it to get to an interesting guest interview – the last catch-up was to get to an episode with Teller, and before that to get to one with George Takei. I won’t just skip to the interviews I want though, because that would mean missing things like an interview with Peter Noone. I had never heard of him before, but it’s one of the best episodes of Penn’s Sunday School they’ve done.

Meeples & Miniatures

I listened to a couple of episodes of this that discussed Dreadball – obviously – and decided it’s not really meant for me. I liked the podcast, but it was a bit long and didn’t really click for me. But apparently, the guys behind Meeples and Miniatures are going to be making a Dreadball podcast soon! That’ll be going straight onto the list. Since I can’t actually think of a reason why I didn’t pick this up (they’re like a calm, quiet, relaxing D6 Generation) as a regular cast, maybe I’ll give it another go.

The Diecast

Shamus Young of Twenty Sided is experimenting with a podcast – I haven’t listened yet, but I’ll try it out. I didn’t like the Spoiler Warning series (I barely got five minutes in), although I normally like commentaries and MST3K style things, I just found it annoying more than anything else. But the podcast will be worth a listen to see if I can add it to my list.

Learning Unit Testing XI – Difficult Terrain Is Difficult

As the title clearly states, difficult terrain is going to be hard. It will involve a replacement of the ‘get distance’ code that takes into account that strict distances are not the same as movement distances – the idea that four inches of distance may cost five, six or more inches of movement (which is what counts for running, charging, and moving in general).

Because of this difficulty, my current inability to devise a solution, and my need to get moving on other things immediately (time on this project is limited, and I would rather move on than get stuck in design hell that maybe I should have sorted out sooner) I will be abandoning the Movement phase for the infinitely more interesting Shooting phase. It actually looks slightly easier, but I’m sure that’ll be remedied when I get to the rules for weapons and skills.

Unlike movement, which started to bog down the Model class, I’m going to try and keep all shooting related code in the shooting manager. Again, having an inkling of what the skills and weapons rules are going to do later, I believe this will make things a lot easier.

The first thing written down is defining who can shoot – Any model can shoot as long as it’s armed with a missile weapon, is not in hand-to-hand combat, can see a target, didn’t run or charge and is not hiding. This seems like a sensible thing to write a checking method for, and a little raft of tests. Time for a new test class, and also (finally) a test helper.

class TestHelper
{
public static IGameManager GetMockGameManager(IModel testModel, IObjectManager objectManager, int numberOfEnemies, int numberOfAllies)
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
List<IModel> modelList = new List<IModel>();
modelList.Add(testModel);
for (int i = 0; i < numberOfAllies; i++)
{
modelList.Add(new Model(testModel.Player, mockGameManager.Object, objectManager));
}
for (int i = 0; i < numberOfEnemies; i++)
{
modelList.Add(new Model(testModel.Player + 1, mockGameManager.Object, objectManager));
}
mockGameManager.Setup(item => item.Models).Returns(modelList);
return mockGameManager.Object;
}
}
[TestClass]
public class ShootingManagerTests
{
[TestMethod]
public void CanShoot_ReturnsTrue_IfEverythingCorrect()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsTrue(shootingTest.CanShoot(model));
}
}

Right, a lot of ‘generate class’ and ‘generate stub’ later (the ctrl+. shortcut is my friend) and the library compiles again. I intend for all missile weapons (that need special functionality not covered by the basic rules) to inherit from MissileWeapon, which ought to cover the majority of things. Weapons is a list of IWeapon (implemented by MissileWeapon), Direction is just an integer describing the angle the model faces (assuming a top-down view), and ShootingManager is quite an empty class at the moment. Following TDD pretty strictly, to pass this test it becomes:

public class ShootingManager
{
public bool CanShoot(Model model)
{
bool canShoot = true;
return canShoot;
}
}

But of course, that’s not quite right. Here’s a few more tests.

[TestMethod]
public void CanShoot_ReturnsFalse_IfRunning()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = true;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfCharging()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = true;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfHiding()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = true;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And what do all those lines of code need to make them pass?

public bool CanShoot(Model model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
return canShoot;
}

It’s almost insulting. The next one should be a bit more of a challenge:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoMissileWeapon()
{
Model model = new Model(1, null, null);
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfOnlyMeleeWeapons()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MeleeWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And these are solved by:

public bool CanShoot(Model model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

Linq makes things a little bit too easy these days… The next test checks if the model can see an opponent:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoEnemyInSight()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 0;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

As expected, it fails. The only difference to the original ‘everything is fine’ test case is the direction that the model is facing – a model can only see in a 90 degree arc to it’s front, so by turning it completely around it should be unable to see the enemy properly. The calculations on the abstract ObjectManager should reflect this, so an extra method in ObjectManager that is exposed (slightly) through Model will help out.

First off – a lot of tests break. This is because the models have been set up with null object managers, which obviously throw exceptions when the call to check them for models in sight occurs. In refactoring to get the first test (pass if all clear) passing, references and parameters were shifted from Model to IModel, things were added to IModel,and in general a bit of housekeeping took place. Here is the new ‘all clear’ test:

[TestMethod]
public void CanShoot_ReturnsTrue_IfEverythingCorrect()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(gameManager.Models);
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsTrue(shootingTest.CanShoot(model));
}

With similar ‘setup’ code to the subsequent tests to get them all passing. The improved ‘new’ test:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoEnemyInSight()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(new List<IModel>());
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 0;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And finally, the code to pass it:

public bool CanShoot(IModel model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
if ((from target in model.GetModelsInSight(90)
where target.Player != model.Player
select target).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

With one small addition to the Model class:

public List<IModel> GetModelsInSight(int angleOfSight)
{
List<IModel> modelsInSight = new List<IModel>();
modelsInSight = _objectManager.GetModelsInSight(this, _gameManager.Models, angleOfSight);
return modelsInSight;
}

Finally, one more test and the ‘who can shoot’ question is completely answered. Models cannot shoot if they’re already in hand-to-hand combat. A simple boolean property (the exact circumstances of being able to set it will be complicated, but that’s a problem for later) on the Model and IModel, adding it as an explicit ‘false’ parameter in the other CanShoot tests, and it’s own test case:

[TestMethod]
public void CanShoot_ReturnsFalse_IfModelInHandToHandCombat()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(gameManager.Models);
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
model.IsInHandToHandCombat = true;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And the complete CanShoot code to pass it:

public bool CanShoot(IModel model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true || model.IsInHandToHandCombat == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
if ((from target in model.GetModelsInSight(90)
where target.Player != model.Player
select target).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

And it leaves me at a good point to finish off for this section. The next section will be the Closest Target rules, which I’ve already given some thought to – but my word count here is already over 1500, so it’s probably best to clock off!

Learning Unit Testing X – Finishing Hiding

Last time, I got the tests for Charging out of the way, and got through a raft of simple checks for Hiding. This time, a few of the more complicated checks.

First off, a model can move around while hiding as long as it remains out of sight. I’m not sure how to be checking every point along the move, but I can check at the end of the movement whether it’s still out of sight.

[TestMethod]
public void Hide_ThrowsExceptionIfInSightAfterMove()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
bool exceptionThrown = false;
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Hide();
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
Assert.IsTrue(testModel.IsHiding);
try
{
testModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
Assert.IsFalse(testModel.IsHiding);
}

The best way to check this is probably to call the Hide method at the end of MoveModel – any change in the model’s visibility will be picked up. Code re-use: excellent!

if (this.IsHiding)
{
this.Hide();
}

But I still don’t get a pass… I also need to set IsHiding to false in the Hide method, when it throws an exception. Then the test goes green.

The next test is that after an enemy model has moved, it might force a model to stop being hidden. I will keep the current action of throwing an exception – this will let the imaginary UI show that hiding has ceased.

[TestMethod]
public void Hide_StopsHidingIfInSightAfterEnemyMove()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Movement = 4;
bool exceptionThrown = false;
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Hide();
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
Assert.IsTrue(testModel.IsHiding);
try
{
enemyModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
Assert.IsFalse(testModel.IsHiding);
}

The code to pass this test should be just adding the following check to the end of MoveModel (as long as Hide is added to the IModel interface).

foreach (IModel enemyModel in (from models in _gameManager.Models
where models.Player != this.Player
select models))
{
enemyModel.Hide();
}

But this doesn’t work – not only does it not work, but it breaks other tests! Now, Charge_SetsIsChargingFlag, MoveModel_CannotMoveFurtherThanModelsMovement and NewTurn_SetsIsChargingToFalse throw exceptions and this test fails on the penultimate assert that the exception was thrown. I believe the error with this test is that the Mock GameManager I’m using is only returning the enemyModel – not the testModel. When I added the testModel to the setup, this test at least passes. The other tests all throw exceptions. This is probably due to the fact that the GameManager is not being correctly set up in each case, to return an empty List<IModel> – as a mock object, it returns null instead and the above code to check for other models fails when passed a null.

By adding in the required setup line to each of those tests, I get 31 passes again.

Finally, a model is automatically forced out of hiding if an enemy model is within it’s Initiative range of the hiding model. This one needs to be checked when the model chooses to hide, and also whenever it moves or the enemy model moves. Since all three of these cause the Hide method to be called, that should probably be where it sits. The following tests should cover off those three situations:

[TestMethod]
public void Hide_CannotHideIfEnemyInInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Location = new LocationPoint(1, 0, 0);
enemyModel.Initiative = 2;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_StopHidingIfModelMovesIntoEnemyInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Location = new LocationPoint(5, 0, 0);
enemyModel.Initiative = 3;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
testModel.IsHiding = true;
testModel.Movement = 4;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_StopHidingIfEnemyMovesWithinInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(5, 0, 0);
enemyModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Initiative = 3;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
testModel.IsHiding = true;
enemyModel.Movement = 4;
bool correctExceptionThrown = false;
try
{
enemyModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}

The passing code sits in Hide, and is very pleasantly simple. Hide becomes very long:

public void Hide()
{
if (this.IsCharging || this.IsRunning)
{
HidingException ex = new HidingException("Cannot hide if charged or ran this turn.");
throw ex;
}
else
{
List<IModel> enemyModels = (from models in this._gameManager.Models
where models.Player != this.Player
&& (this._objectManager.GetLineOfSight(models, this) > 0.6 || this.GetDistanceFrom(models.Location.X, models.Location.Y, models.Location.Z) <= models.Initiative)
select models).ToList();
if (enemyModels.Count > 0)
{
this.IsHiding = false;
HidingException ex = new HidingException("Cannot hide in sight or Initiative range of enemy models.");
ex.EnemyModels = enemyModels;
throw ex;
}
else
{
this.IsHiding = true;
}
}
}

But this breaks several other tests. The reason is that some of the previously written tests are not setting locations for the enemy and test models, and the distance between them (zero) is always equal to or less than the default Initiative value (also zero). Changing the tests to give them a bit of space fixes this problem.

Since a model can remain hidden for several successive turns, it doesn’t need to reset the IsHiding flag – Hiding for all hidden models is checked whenever a model is moved, so it will be taken out of hiding when a player wishes or when it is chosen.

Next time, I move off of page 11, but I’m not sure where to yet…

Learning Unit Testing IX – Moving On With Movement

Having gotten those knotty problems with world management, distances, directions, etc all out of the way I can finally move off of page 10. So what’s next? Page 11! Hooray!

It begins with a description of a charge move. A charge works like a run, at double-move rate, with the model (hopefully) ending up in contact with an enemy, or with a low wall that is also in contact with the enemy. The movement side of things should be fairly easy, but describing ‘base contact’ might be slightly more difficult.

In the real game, a model’s base is usually a circle 25mm in diameter. This is close enough to one inch to be treated as one of the arbitrary units I’m using for movement and measurement, so a model can be described as having a width of 1. If I choose the location to describe the centre-point of a model’s base, then ‘base contact’ would be a point equal to half the charger’s width plus half the target’s width, to allow for future models that may be bigger or smaller than a normal one (I’m fondly thinking of Ogryns!)

I started skirting around the issue slightly in the last post, but I need to seriously consider scenery and models as things with width and height, more than points on a virtual graph. The scenery will also need a different method of determining base contact, since it won’t often have a circular base.

It’s taking me a while to work out exactly which direction (no pun intended) to go with this. A charge sounds exactly like a regular run move, except you can (and are expected to!) get within 8” of an enemy model without stopping, and it declares that the model “Can do nothing for the rest of the turn.” To that end, I believe that only three new tests are needed, on a ‘charge’ method – one that makes sure a charging model can approach within 8” of an enemy, one that checks that an ‘isCharging’ flag is set so that the model can’t take any more actions this turn, and one that checks that that flag is removed at the beginning of a turn.

The first test – that the model doesn’t stop moving close to an enemy – is almost identical to the one that checks that it does stop moving close to an enemy, but with a different expected final position and no exception thrown.

[TestMethod]
public void Charge_CanGetWithin8InchesOfEnemy()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
mockObjectManager.Setup(item => item.GetPointOfIntersection(testModel.Location, It.IsAny<LocationPoint>(), enemyModel.Location, 8)).Returns(new LocationPoint(1, 0, 0));
mockObjectManager.Setup(item => item.GetLineOfSight(testModel, enemyModel)).Returns(1);
testModel.Charge(8, 0, 0);
}
catch (MovementException ex)
{
exceptionThrown = true;
}
Assert.IsFalse(exceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}

The code to pass this test is extremely simple:

private bool _isCharging = false;
public void Charge(float positionX, float positionY, float positionZ)
{
_isCharging = true;
MoveModel(positionX, positionY, positionZ);
}

And a quick change to the ValidateMove method to check if the model is charging before validating the ‘within 8” of an enemy’ rule:

if (this.TotalDistanceMoved + distanceToPoint > this.Movement && _isCharging == false)

I almost feel silly for thinking it would be any harder than that, but then I was originally worrying about the base sizes, low wall restriction, etc, that is all part of ‘being in base contact’ – as far as Movement is concerned, it doesn’t matter if the models are in base contact after a charge, only that a charge was attempted. The next test, then, checks that the flag is set:

[TestMethod]
public void Charge_SetsIsChargingFlag()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
testModel.Charge(8, 0, 0);
Assert.IsTrue(testModel.IsCharging);
}

The code only needed to change the private _isCharging to a public IsCharging property, and again – straight into the pass. To make sure the NewTurn method resets the charging flag:

[TestMethod]
public void NewTurn_SetsIsChargingToFalse()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Charge(8, 0, 0);
Assert.IsTrue(testModel.IsCharging);
testModel.NewTurn();
Assert.IsFalse(testModel.IsCharging);
}

Code to pass that test is just insultingly simple. At this time, I realised that the IsRunning flag might not have been set back to false at the beginning of a new turn – there’s no test for it, so I’ll add that in now.

[TestMethod]
public void NewTurn_SetsIsRunningToFalse()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.MoveModel(8, 0, 0);
Assert.IsTrue(testModel.IsRunning);
testModel.NewTurn();
Assert.IsFalse(testModel.IsRunning);
}

And as I predicted – it fails! The passing code should, again, be fairly easy to figure out. So I now have all the basics of charging, without the ‘is in base contact’ checks which will mostly be mathematical functions, and abstracted out without really implementing them (as I decided earlier).

The next challenge is Hiding, then we can move away from page 11 – much faster than getting away from page 10 was, at any rate! As I see it, the following things are necessary to check for hiding:

  • A model can choose to hide if it ends it’s turn in ‘reasonable’ cover
  • A model can move about and stay hidden, as long as it doesn’t leave the ‘reasonable’ cover.
  • A model cannot run or charge and hide in the same turn.
  • If an enemy model moves to a position it can see the hiding model, it ceases to be hidden.
  • A model ceases to be hidden if an enemy is within it’s Initiative value in inches of the model.

I will define ‘reasonable’ cover as being in at least 40% cover – this value could easily be tweaked later. I had decided while brainstorming before that line-of-sight shouldn’t return a boolean value, rather a percentage of the target that is visible. In systems that can determine only ‘visible’ and ‘not visible’, the IObjectManager would obviously return 0 and 1 and nothing in between. More subtle systems would give a range of values, meaning that cover saves (when I get to shooting) will take account of partial cover, heavy cover, etc. The first test then will check line of sight from every enemy, to make sure that it is not more than 60% visible to any of them.

[TestMethod]
public void Hide_SetsFlagIfInReasonableCover()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0.5f);
testModel.Hide();
}
catch (HidingException ex)
{
exceptionThrown = true;
}
Assert.IsFalse(exceptionThrown);
Assert.IsTrue(testModel.IsHiding); }

Code to pass this test:

public void Hide()
{
List<IModel> enemyModels = (from models in this._gameManager.Models
where models.Player != this.Player
&& this._objectManager.GetLineOfSight(models, this) > 0.6
select models).ToList();
if (enemyModels.Count > 0)
{
HidingException ex = new HidingException();
ex.EnemyModels = enemyModels;
throw ex;
}
else
{
this.IsHiding = true;
}
}

Using some lovely LINQy goodness! The next test:

[TestMethod]
public void Hide_ThrowsExceptionIfInSight()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
testModel.Hide();
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
}

Needs no modification. Maybe I went a bit too far with the code writing, since I knew what the test would be in advance? I played with the figures to make sure that the test fails when it should.

The following tests should prevent the Hiding flag staying set when running or charging:

[TestMethod]
public void Hide_RemoveHidingFlagWhenRunning()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsHiding = true;
testModel.Movement = 4;
testModel.MoveModel(6, 0, 0);
Assert.IsFalse(testModel.IsHiding);
}
[TestMethod]
public void Hide_RemoveHidingFlagWhenCharging()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsHiding = true;
testModel.Movement = 4;
testModel.Charge(6, 0, 0);
Assert.IsFalse(testModel.IsHiding);
}

The code for both these tests is simple – change MoveModel and Charge to look like:

public void MoveModel(float positionX, float positionY, float positionZ)
{
try
{
ValidateMove(ref positionX, ref positionY, ref positionZ);
}
catch (Exception ex)
{
throw;
}
finally
{
this.TotalDistanceMoved += GetDistanceFrom(positionX, positionY, positionZ);
this.Location.X = positionX;
this.Location.Y = positionY;
this.Location.Z = positionZ;
if (this.TotalDistanceMoved > this.Movement)
{
this.IsHiding = false;
this.IsRunning = true;
}
}
}
public void Charge(float positionX, float positionY, float positionZ)
{
IsHiding = false;
IsCharging = true;
MoveModel(positionX, positionY, positionZ);
}

The next two tests check that a model can’t hide if it charged or ran this turn:

[TestMethod]
public void Hide_CannotHideIfRanInSameTurn()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsRunning = true;
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void Hide_CannotHideIfChargedInSameTurn()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsCharging = true;
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}

I’m really liking how simple these tests are to pass at the moment. The code to solve both of those tests goes at the top of the Hide method, and is just a quick check:

if (this.IsCharging || this.IsRunning)
{
HidingException ex = new HidingException("Cannot hide if charged or ran this turn.");
throw ex;
}

This is getting a bit too long (I’m thinking that 2000 words, including code, should be a maximum limit on these). I’ll continue more Hiding tests next time!

Learning Unit Testing VIII – Emergent Design

I’ve been bracing myself for this moment since I started the project – I’m coming to believe that I’ve been heading in a slightly wrong direction.

Part of TDD is the idea of ‘emergent design’, and letting the correct design emerge from the process of writing minimal code to pass tests. At the same time, it’s necessary to keep an eye on the bigger picture so you know where exactly the code should be written.

I’ve been making the MoveModel method into a huge monster, that checks all sorts of things, and as I started investigating how to implement line of sight, I realised that this functionality should probably be moved out into some sort of utility class. MoveModel itself is now checking distances between two points (this will be duplicated later), proximity detection (probably to be used later), and as I said – was about to take on line of sight. All these details could be worked out mathematically as I was doing them, but some frameworks (such as XNA) might provide better ways to calculate them, with things such as Rays, or… something else XNAish.

The best way to handle that would be to refactor all the ‘utility’ calculations into a separate class, exposed via an interface so that it can be swapped out. That way, I can abstract out and mock all the calculations in MoveModel to deal more with the situation parameters and appropriate responses and less about the calculations themselves. At the same time, I can write tests for this new utility class so that I can test the purely mathematical aspects of the same calculations. The interactions become easier (true, false, and integer responses rather than the broad spectrum of mathematical output) since I don’t have to test multiple configurations and situation-specific responses, just the two separate things that should be behaving.

The other benefit will be that if I eventually do take this library over to an XNA frontend, I can swap out that mathematical calculator for something more efficient for the framework to use. But the basic mathematical way will still be available if I choose instead to port it to Silverlight.

I also took this opportunity to move the X, Y and Z co-ordinates into a separate class – LocationPoint.

Here’s the set of tests for MoveModel:

[TestClass]
public class ModelTests
{
[TestMethod]
public void NewTurn_SetsDistanceMovedToZero()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.TotalDistanceMoved = 4;
testModel.NewTurn();
Assert.AreEqual(0, testModel.TotalDistanceMoved);
}
[TestMethod]
public void MoveModel_PositionHasChanged()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 2;
float newY = 2;
float newZ = 2;
testModel.MoveModel(newX, newY, newZ);
Assert.AreEqual(2, testModel.Location.X);
Assert.AreEqual(2, testModel.Location.Y);
Assert.AreEqual(2, testModel.Location.Z);
Assert.IsFalse(testModel.IsRunning);
}
[TestMethod]
public void MoveModel_TotalMovementInASingleTurnCannotExceedModelMovement_ThrowsMovementException()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
try
{
testModel.MoveModel(0, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_MakeTwoSmallMovementsWithoutGoingOverMovementRate()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 1;
float newY = 1;
float newZ = 0;
try
{
testModel.MoveModel(newX, newY, newZ);
testModel.MoveModel(0, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_CannotMoveFurtherThanModelsMovement()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
float newX = 5;
float newY = 6;
float newZ = 3;
try
{
testModel.MoveModel(newX, newY, newZ);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_MovesDistanceOverMovementRateAndSetsIsRunningFlag()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
Assert.IsTrue(testModel.IsRunning);
}
[TestMethod]
public void MoveModel_StopsRunningWithin8InchesOfEnemyModel()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
mockObjectManager.Setup(item => item.GetPointOfIntersection(testModel.Location, It.IsAny<LocationPoint>(), enemyModel.Location, 8)).Returns(new LocationPoint(1, 0, 0));
mockObjectManager.Setup(item => item.GetLineOfSight(testModel, enemyModel)).Returns(1);
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(1, ex.FinalPosition.X);
Assert.AreEqual(0, ex.FinalPosition.Y);
Assert.AreEqual(0, ex.FinalPosition.Z);
}
Assert.IsTrue(correctExceptionThrown);
Assert.AreEqual(1, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithEnemyMoreThan8InchesAway()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 18;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesMovingWithin8InchesOfEnemyModelNotRunning()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(3, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(3, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithin8InchesOfFriendlyModel()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model friendlyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
friendlyModel.Location.X = 9;
friendlyModel.Location.Y = 0;
friendlyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { friendlyModel });
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithin8InchesOfEnemyModelIfOutOfSight()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 12;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Mock<IScenery> mockScenery = new Mock<IScenery>();
mockScenery.Setup(item => item.IsBlocking(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(true);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
mockGameManager.Setup(item => item.SceneryObjects).Returns(new List<IScenery>() { mockScenery.Object });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
}

And the code needed in MoveModel itself:

public void MoveModel(float positionX, float positionY, float positionZ)
{
try
{
ValidateMove(ref positionX, ref positionY, ref positionZ);
}
catch (Exception ex)
{
throw;
}
finally
{
this.TotalDistanceMoved += GetDistanceFrom(positionX, positionY, positionZ);
this.Location.X = positionX;
this.Location.Y = positionY;
this.Location.Z = positionZ;
if (this.TotalDistanceMoved > this.Movement)
{
this.IsRunning = true;
}
}
}
private bool ValidateMove(ref float positionX, ref float positionY, ref float positionZ)
{
double distanceToPoint = GetDistanceFrom(positionX, positionY, positionZ);
if (distanceToPoint + this.TotalDistanceMoved > this.Movement * 2)
{
MovementException ex = new MovementException("The model cannot move further than it's Movement rate.");
ex.FinalPosition.X = this.Location.X;
ex.FinalPosition.Y = this.Location.Y;
ex.FinalPosition.Z = this.Location.Z;
throw ex;
}
if (this.TotalDistanceMoved + distanceToPoint > this.Movement)
{
foreach (IModel enemyModel in _gameManager.Models.Where(item => item.Player != this.Player))
{
LocationPoint intersectionPoint = _objectManager.GetPointOfIntersection(this.Location, new LocationPoint(positionX, positionY, positionZ), enemyModel.Location, 8);
if (intersectionPoint != null)
{
if (_objectManager.GetLineOfSight(this, enemyModel) > 0)
{
MovementException ex = new MovementException("The model cannot run within 8\" of an enemy model.");
ex.FinalPosition = intersectionPoint;
positionX = intersectionPoint.X;
positionY = intersectionPoint.Y;
positionZ = intersectionPoint.Z;
throw ex;
}
}
}
}
return true;
}

The lesson I’ve learned from this as far as emergent design goes is that I should be more willing to abstract something out if it doesn’t look like it belongs, and be prepared to program against interfaces that are not implemented yet. I believe that’s the way TDD works, and will keep code exactly where it needs to be and not spread around (as it was starting to do in the Model class…)

Learning Unit Testing VII – Running and Redesigning

I can see this page 10 being a pretty big thorn in my side. After stating fairly clearly

models can move up to their move rate

under the ‘Moving’ heading, it then says

A running fighter can move at double speed: 8″ rather than 4″, for example.

This is going to have a fairly large impact on the tests involved. The test for exceeding total movement (both in one and two moves) will only throw an exception if the total movement is double the model’s Movement rate now. In addition, a new test is going to have to be added to ensure that moving over the Movement rate sets an ‘IsRunning’ flag to true. The first test to add would be one that allows a model to move more than it’s Movement rate, but sets the IsRunning flag.

[TestMethod]
public void MoveModel_MovesDistanceOverMovementRateAndSetsIsRunningFlag()
{
Model testModel = new Model();
testModel.Movement = 4;
testModel.PositionX = 0;
testModel.PositionY = 0;
testModel.PositionZ = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
Assert.IsTrue(testModel.IsRunning);
}

Even with the correct code added to MoveModel –

if (this.TotalDistanceMoved > this.Movement)
{
this.IsRunning = true;
}

– this doesn’t work. Because ValidateMove is throwing an exception (as we designed in earlier). So ValidateMove has to allow up to twice the MovementRate.

if (GetDistanceFrom(positionX, positionY, positionZ) + this.TotalDistanceMoved > this.Movement * 2)
{
throw new ArgumentException("The model cannot move further than it's Movement rate.");
}

Now, all the tests pass. But should they be? Checking my working, the MoveModel_CannotMoveFurtherThanModelsMovement test is moving the model more than twice it’s movement rate. So it is correct to throw an exception, and therefore pass the test. Anything testing to stay beneath the model’s Movement rate is obviously going to be beneath it’s doubled Movement rate, so they will continue to pass. MoveModel_TotalMovementInASingleTurn… that tests whether two movements that combined make more than the model’s Movement is also working correctly. But I’ve noticed I had an error in that test:

[TestMethod]
public void MoveModel_TotalMovementInASingleTurnCannotExceedModelMovement_ThrowsArgumentException()
{
bool correctExceptionThrown = false;
try
{
Model testModel = new Model();
testModel.Movement = 4;
testModel.PositionX = 0;
testModel.PositionY = 0;
testModel.PositionZ = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
testModel.MoveModel(0, 0, 0);
}
catch (ArgumentException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}

The try catch was working on both MoveModel calls – and those values (after the calculation fix a couple of posts back) would have sent it way over the Movement on the first move, not the second. Moving the try…catch so that it only covers the second call to MoveModel would check that it’s failing in precisely the right place. By reversing my change to ValidateMove, I can confirm that the test would have failed before if the try…catch was in the right place. Putting it back in, and it throws an exception on the second MoveModel call, just as it should do. All the tests pass, and I’m a little more comfortable about them testing the right thing.

Lesson learned: Only test exactly the line you expect to break things.

The rest of the ‘Running’ section mentions not being able to shoot – this is something that we can cover in the Shooting section (after Movement), and isn’t important right now. The next bit that should matter is that a running model must stop 8 units away from an enemy model that he can see. This brings a number of things into play immediately:

  1. Can we identify models as being enemies?
  2. Can we identify which models can see others?
  3. How do we perform the sight checks all along it’s movement to work out if it can see the enemy (they may not be in sight at the beginning of the move, only halfway along it)?
  4. What action should be taken if the model’s movement is disrupted – should it still count as running? How can it be prevented from moving further?

Before we write tests, we should explore the problem a bit further.

Essentially, the enemy is at the centre of a circle 16 units in diameter (radius of 8). The active model’s path may intersect the circle at some point. If it does so, the active model must stop at the point along that path nearest to his starting point, providing that he can draw a line of sight to the enemy model at the centre of the circle.

So we only really need to work out if any point of the active model’s path intersects the enemy ‘disruption’ circles, and check those sections of the path for line-of-sight to the centre of the circle.

Learning Unit Testing VI – Code Coverage

Before I get into finally finishing off that blasted page 10, I thought I’d go through a code coverage run to see how I was doing. Test Driven Development, see, everything should be covered by a test.

image

7.41% of the code is not covered by tests! I must be doing this wrong…

image_3

Phew, that was a relief. Turns out all of that uncovered code is in the WrongPhaseException I created from the Exception snippit without thinking about it. Activating the code coverage colouring in the code shows me what I’ve missed:

image_4

Because I only use one constructor out of a possible four, it counts as only 25% coverage and brings my average code coverage way down.

If I was to remove all those extra constructors (and leave them to the default Exception behaviour), would it improve my code coverage score?

image_5

Absolutely. It might be a bit like cheating (those methods are still not covered by tests), but since they’re core parts of the framework it doesn’t feel necessary to me. Short and sweet, on to part VII!

This is a learning project I am documenting in order to teach myself TDD and unit testing – as I publish this, I have already written many parts in advance but I want to know what I’m doing wrong! If you see improvements or corrections, either to the code or the process, please leave a comment and let me know! Introduction to this project can be found here.

Learning Unit Testing V – Refactoring Mistakes

I implied in the last post that I had made a mistake when I moved the MoveModel code into the Model class from the MovementManager class. Now, tests on the MovementManager class are actually testing functionality in the Model class. I also discovered that I am not properly testing the ‘GetDistanceFrom’ method with known data at all. This will have to be corrected.

Since I already have Model implementing an IModel interface, it’ll be easy enough to mock the Model part in the MovementManager. To see what tests are reaching into Model.MoveModel, I can just alter that method to throw an exception and see which tests fail.

image

Since this functionality has been moved to the Model class, these tests should actually be made against the Model class itself. Simple? Yes, but incorrect, as I found out next – it still fails on one condition and checking further, I don’t believe it’s checking the other one correctly. The validation of whether or not a model may make a move (ie, the distance is still under it’s Movement rate) is done in the MovementManager. My two options at this point are: move the validation back to the MovementManager and do a lot of mocking around the Model, or to move that validation into the Model as a ValidateMove method. Then the movement manager really becomes a mere progress tracker for the Movement phase… but I think that’s probably the best idea in this situation. Just one more test to move over (MoveModel_CannotMoveFurtherThanModelsMovement), then the GetDistanceFrom method needs to be tested. I think the following cases will need to be covered:

  • Full three-dimensional movement (all values change)
  • Two-dimensional movement (one value doesn’t change)
  • One-dimensional movement (only one value does change)
  • Cover reverse cases of each of the above (so the direction is backwards)

This test (worked on with a calculator and doodles to prove my working), however:

[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenAllValuesChange()
{
Model testModel = new Model();
testModel.PositionX = 1;
testModel.PositionY = 3;
testModel.PositionZ = 4;
double result = testModel.GetDistanceFrom(2, 5, 7);
Assert.AreEqual(3.74, Math.Round(result, 2));
}

Shows me that either my test calculation is wrong or my original working is wrong. In the GetDistanceFrom method, this line

distance = Math.Sqrt(Math.Sqrt((differenceX * differenceX) + (differenceY * differenceY)) + (differenceZ * differenceZ));

Should actually be

distance = Math.Sqrt((differenceX * differenceX) + (differenceY * differenceY) + (differenceZ * differenceZ));

So I got the calculation wrong. Now the test passes, but another one breaks.

image_3

This is because that movement calculation now requires the model to move further than it’s allowed distance. Fixing that test’s values (from 3, 4, 5 to 2, 2, 2) and adding in the following tests:

[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenTwoValuesChange()
{
Model testModel = new Model();
testModel.PositionX = 1;
testModel.PositionY = 3;
testModel.PositionZ = 4;
double result = testModel.GetDistanceFrom(1, 5, 7);
Assert.AreEqual(3.61, Math.Round(result, 2));
}
[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenOneValueChanges()
{
Model testModel = new Model();
testModel.PositionX = 1;
testModel.PositionY = 3;
testModel.PositionZ = 4;
double result = testModel.GetDistanceFrom(1, 3, 7);
Assert.AreEqual(3, Math.Round(result, 2));
}
[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenAllValuesChange_Reversed()
{
Model testModel = new Model();
testModel.PositionX = 2;
testModel.PositionY = 5;
testModel.PositionZ = 7;
double result = testModel.GetDistanceFrom(1, 3, 4);
Assert.AreEqual(3.74, Math.Round(result, 2));
}
[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenTwoValuesChange_Reversed()
{
Model testModel = new Model();
testModel.PositionX = 1;
testModel.PositionY = 5;
testModel.PositionZ = 7;
double result = testModel.GetDistanceFrom(1, 3, 4);
Assert.AreEqual(3.61, Math.Round(result, 2));
}
[TestMethod]
public void GetDistanceFrom_CorrectAnswerWhenOneValueChanges_Reversed()
{
Model testModel = new Model();
testModel.PositionX = 1;
testModel.PositionY = 3;
testModel.PositionZ = 7;
double result = testModel.GetDistanceFrom(1, 3, 4);
Assert.AreEqual(3, Math.Round(result, 2));
}

Gives me 19 passes out of 19 tests. Excellent – I was expecting some of the 0-distance values being squared and rooted to throw some sort of calculation exception in .Net, but I can get along with this result.

This leaves me with my refactoring mess cleaned up, a calculation error solved, a method I somehow missed tests for covered properly, and all ready to tackle the last part of page 10 – a much longer page than I had initially expected. “Ooh look”, said the me at the beginning of the week, “half the page is picture and prose, and the other half is mostly descriptive. One or two posts to talk about design ideas and I’ll be on page 20 in a fortnight!” Isn’t hindsight awesome.

This is a learning project I am documenting in order to teach myself TDD and unit testing – as I publish this, I have already written many parts in advance but I want to know what I’m doing wrong! If you see improvements or corrections, either to the code or the process, please leave a comment and let me know! Introduction to this project can be found here.