The hilarious thing I realized after doing the last session... I don't think I need CosmosAccountName
... OH WELL...
I do need CosmosCollectionName
; so let's use our cheat test base and make that.
... forgot to start the script again... I love that I wait for the sound.
Following the recipie to move the class and it's created!
The BULK
OK... so... The next step is gonna be a bit of a big lift. Looking at a previously implemented bit; I need to create a CosmosContainerAdapter
which houses a lot of the cosmos interactions. WHich in my examples I don't do a great segregtion of concepts. So... gonna do that here. Which should make for an easier to test implementation.
OK.. I'm gonna first do the scribe; so I first need a CosmosContainerUpsertAdapter
.
I created the "Exists" test... then I paused it and moved the files.
I get the strict steps... but... uhh... lazy.
And... as I look at my refernece... yeah... Kinda cheating. :)
ANYWAY - as I look at it; there's a return type I want to use, so I need to TDD that first.
It's a CosmosItemResponse<T>
; which basically performs similar behavior to the cosmos ItemResponse<T>
but; I don't want 3rd party SDKs scattered through my code.
This is gonna be a ToSystemType
that has some aditional behaviors. I'm gonna use the base class created for these.
I'm pausing for moving classes now. It's ... less annoying. I like to know how to do the dance; but doesn't mean we have to do it every time.
I added this test
[TestMethod, TestCategory("unit")]
public void Value_PropertyShouldExist()
{
//arrange
CosmosItemResponse<object> subject = new TestCosmosItemResponse<object>();
//act
object _ = subject.Value;
//assert
}
to let the tool create the Value property for me. I want it to be get
only; and it gave me an option to do that. Should I use it; or should I later add a test to force that change?
I'm opting for the later force; but it's an interesting question.
Hrm... it's barfing on me;
... because I short cut'd and the ToSystemType aspect of the CosmosItemResponse is borked... I took shortcuts... don't take shortcuts.
OK; it's pause-fixed. Now I need to overide the Value property; which... uhh... can't... really... soo... I need to make it virtual to implement; then abstract.
Couple tests later and have that. Now I need the same abstract dance with a StatusCode.
I'm wondering how it'll feel to do that with just the "ShouldBeAbstract" test. Ewwww... I don't like it. I can't have the tools create it for me through reflection.
I am seeing how it feels to default create it as abstract...
It feels dirty. That's code there's no test driving it. Removed.
Seeing what happens if I try to go straight to Abstract. Should break.
Yep. My test impl doesn't have the method, so it breaks.
Doing the same few tests.
I know reading this is boring. I'm just typing out my experience with TCR as I'm doing it. I'm sure I'll give a few talks about it; but I don't know what's gonna happen and ... I don't wanna make a big production with this. It's a focus on TCR, not blogging, to get a reasonable system fully implemented with TCR.
Now I need a method to determine if the status code is a success.
The tests I'm starting with for functionality are
[TestMethod, TestCategory("unit")]
public void IsSuccessfulStatusCode_ShouldReturnTrueFor200()
{
//arrange
CosmosItemResponse<object> subject = new TestCosmosItemResponse<object>(null, HttpStatusCode.OK);
//act
bool actual = subject.IsSuccessfulStatusCode();
//assert
_ = actual.Should().BeTrue();
}
[TestMethod, TestCategory("unit")]
public void IsSuccessfulStatusCode_ShouldReturnFalseFor199()
{
//arrange
CosmosItemResponse<object> subject = new TestCosmosItemResponse<object>(null, (HttpStatusCode)199);
//act
bool actual = subject.IsSuccessfulStatusCode();
//assert
_ = actual.Should().BeFalse();
}
which is testing the two side of the lower boundary.
I added this for the upper bound
[TestMethod, TestCategory("unit")]
public void IsSuccessfulStatusCode_ShouldReturnTrueFor299()
{
//arrange
CosmosItemResponse<object> subject = new TestCosmosItemResponse<object>(null, (HttpStatusCode)299);
//act
bool actual = subject.IsSuccessfulStatusCode();
//assert
_ = actual.Should().BeTrue();
}
and it insta-passed.
Which... DUH given
public bool IsSuccessfulStatusCode()
{
return 200 <= (int)StatusCode;
}
So... I need the failure case first.
[TestMethod, TestCategory("unit")]
public void IsSuccessfulStatusCode_ShouldReturnFalseFor300()
{
//arrange
CosmosItemResponse<object> subject = new TestCosmosItemResponse<object>(null, (HttpStatusCode)300);
//act
bool actual = subject.IsSuccessfulStatusCode();
//assert
_ = actual.Should().BeFalse();
}
all's fair
public bool IsSuccessfulStatusCode()
{
if ((int)StatusCode == 300) return false;
return 200 <= (int)StatusCode;
}
NOW we do the 299 cause.... which still passes. Whatever. Now I'll just fix it.
Don't do this; triangulate!
I have the boundary conditions... I could triangulate... fine... I will add a 500.
Added; then generalized.
public bool IsSuccessfulStatusCode() => 200 <= (int)StatusCode && (int)StatusCode <= 299;
I like having the negated version of a lot of booleans so I can write my code in a way it reads properly... mostly to avoid the !
for turning "false" to "true". Too small.
If you look closely at some commits; you can see more not-triangulating.
The last bit is actually implementing the AsSystemType
to return the Value
I am usin copilot a lot for quick reflection tests.
Letting copilot document it for me gives me
/// <summary>
/// Represents a response from a Cosmos DB item operation.
/// </summary>
/// <typeparam name="T">The type of the item.</typeparam>
public abstract class CosmosItemResponse<T> : ToSystemType<T>
{
/// <summary>
/// Gets the value of the item.
/// </summary>
public abstract T Value { get; }
/// <summary>
/// Gets the HTTP status code of the response.
/// </summary>
public abstract HttpStatusCode StatusCode { get; }
/// <summary>
/// Determines whether the status code indicates a successful response.
/// </summary>
/// <returns><c>true</c> if the status code is between 200 and 299; otherwise, <c>false</c>.</returns>
public bool IsSuccessfulStatusCode() => 200 <= (int)StatusCode && (int)StatusCode <= 299;
/// <summary>
/// Determines whether the status code indicates an unsuccessful response.
/// </summary>
/// <returns><c>true</c> if the status code is not between 200 and 299; otherwise, <c>false</c>.</returns>
public bool IsNotSuccessfulStatusCode() => IsSuccessfulStatusCode() is false;
/// <summary>
/// Converts the response to its system type representation.
/// </summary>
/// <returns>The value of the item.</returns>
public override T AsSystemType() => Value;
}
My next thing... I think... is the Upserter... which if I follow my current design is gonna require a ContainerFake
. We can argue about it being a Fake,Spy,Mock,Bleep,Bloop,Blort. It's a TestDouble; and I'm using a 'Fake' suffix for it.
AND fighting updates... RIGHT... I wanted to add the cosmoslib...
It's late; last test to make sure the container is called.
It's still giving me build issues... BOOOOO.
ANNNNNNNDDDDDD - I'm too tired to continue. I know when I hit that limit. This is still fun. Gotta recreate some base level stuff I never touch anymore... 'cause I created it already. But it's a fun exercise.