Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot find good ways to test Created AtLocation #247

Closed
foresightyj opened this Issue Jan 16, 2016 · 12 comments

Comments

Projects
None yet
2 participants
@foresightyj
Copy link

foresightyj commented Jan 16, 2016

I have a post action that returns 201 Created with a Location header and an empty body. Basically I want to write my test like this:

.ShouldReturn()
.Created()
.AtLocation(loc => loc.WithAbsolutePath("/api/v1/friends/_outgoing/%d+"));

I don't care about the actual value of the ID (%d) there, as long as it is a number. I wish I could write a regular expression string like that. But this is not possible. The .At<FriendController> method also requires explicitly supplying an ID.

Or, I wish I could write something like this:

.AtLocation(loc =>
{
    string location = loc.Value;
    Assert.IsTrue(location.ToLower().StartsWith("/api/v1/friends/_outgoing/"));
})

I also tried to get hold of a reference to the response message so I could manually assert myself but I could find a method called AndProvideTheHttpResponseMessage but it wasn't there.

image

I'd prefer AndProvideTheHttpResponseMessage method there so I can read the actual ID and go on testing if the uri specified at Location returns 200.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 16, 2016

@foresightyj Will this method work for your case:

MyWebApi
    .Controller<WebApiController>()
    .Calling(c => c.SomeAction())
    .ShouldReturn()
    .Created()
    .AtLocation("http://somehost.com/someuri/1?query=someQuery");

I am currently thinking of a way to test parts of strings everywhere.

About the HttpResponseMessage - it will be hard for controller testing because it will require a lot of pipeline mocking and it is not the point of the unit test. This is why integration tests are there. You can use them. I will think of a way to add it to the controller but it may not be the same HTTP response message as the one you will get on calling the API server.

@foresightyj

This comment has been minimized.

Copy link
Author

foresightyj commented Jan 18, 2016

Thanks. I didn't know all the complexities in HttpResponseMessage.

AtLocation itself doesn't work for me as I cannot provide an exact uri string (since I don't know the ID).

I don't need the complete HttpResponseMessage, I only need a way to read uri in the Location header in a Created 201 Response. Is there a way to read it in the current version?

I already used the Integration Test in MyTested.WebApi. Will resort to that if unit testing is impossible.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 18, 2016

@foresightyj Integration test is the way here. Otherwise, you need to provide a mocked ID, which will come later in the string URL. Or am I missing something? Can you provide some sort of code sample to see the case you are trying to test?

@ivaylokenov ivaylokenov added the feature label Jan 18, 2016

@ivaylokenov ivaylokenov added this to the Version 1.3 milestone Jan 18, 2016

@ivaylokenov ivaylokenov self-assigned this Jan 18, 2016

@foresightyj

This comment has been minimized.

Copy link
Author

foresightyj commented Jan 18, 2016

MyTestedWebApiCreated201.zip

I provided a minimal test case, which is somewhat similar to my actual project.

I realized that my unit test might deviated from a typical unit test a bit.

My project models a social network which has users, friendships, posts, comments, etc. I started without the persistent layer so I could concentrate on the business layer + presentation layer first. For demo purpose, I set up a large graph of interconnected domain objects in memory, in which a few users and their friendships exist beforehand. In Application_Start, I used Ninject to inject a singleton copy of these objects to controllers so state is maintained across requests ( ignore thread safety) until the server restarts.

I have a typical layered architecture: controller --> service layer --> repositories. Repositories read from those in memory objects directly. For every test case, I will initialize a new copy of the graph of objects, instead of mocking just enough data for that test.

Back to the 201 Created example, when I created something, the newly created objects is inserted into a collection inside the graph of in memory objects. Unless I dig into these objects, I would not find the newly created ID.

Sorry for such a long reply. It is OK if it does not make sense to you. I also had a hard time to explain it because I am not sure if someone has done something similar before.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 18, 2016

@foresightyj I believe you need to mock your database object, which the controller is using. Then set it to always apply constant ID when adding object and then test with it. If this does not work for you, I will implement string tester with StartsWith for example. This is more of mocking issue rather that the unit test itself.

@foresightyj

This comment has been minimized.

Copy link
Author

foresightyj commented Jan 19, 2016

I already mocked the database (which is what I mentioned as the graph of interconnected domain objects in memory). This mocked database together with repositories that access it is both used for unit test/integration test as well as the actual deployment. So the repository is not mocked ad hoc but is one that I've written beforehand that has to support for both test and deployment.

Probably very few people have done things this way so my use case is not very generic. Feel free to ignore. Thanks.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 19, 2016

@foresightyj I will add string test builder which will allow to test all strings with StartsWith, EndsWith and so on, so it will work for your case. Thank you for using the library and making sugestions. 👍

@foresightyj

This comment has been minimized.

Copy link
Author

foresightyj commented Jan 20, 2016

@ivaylokenov I really appreciate your kindness in supporting that.

I absolutely love this library and it greatly improved the unit/integration test experience in my team. I learned a lot about Web API and OWIN's internals while using this library.

Keep up the good work. I will read the source code when I am less busy and hopefully can contribute a bit via pull requests some day.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 20, 2016

@foresightyj You are welcome and thank you for the kind words. I am glad the library helps peope write tests faster and easier. More updates/libraries are comming.

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 20, 2016

@foresightyj Can I put your comment as a testimonial on the project's web site - http://mytestedasp.net/ ?
If yes, can I have your name, job title or whatever information you are willing to provide. Thank you!

@foresightyj

This comment has been minimized.

Copy link
Author

foresightyj commented Jan 21, 2016

No problem. I work for a tiny startup in China:

Name: Yuan Jian
Company: Jiangsu HuoHuo Network Technology Co., Ltd. (Nanjing, China)
Job title: Project Director
The number of people in the dev team: 5

ivaylokenov added a commit that referenced this issue Jan 23, 2016

ivaylokenov added a commit that referenced this issue Jan 23, 2016

@ivaylokenov ivaylokenov added the closed label Jan 23, 2016

@ivaylokenov

This comment has been minimized.

Copy link
Owner

ivaylokenov commented Jan 23, 2016

@foresightyj Implemented in version 1.2.1. You can update the package. There is another method AtLocationPassing which allows predicate assertions.

Thank you for the information. Will update the site soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.