Elixir mock only one function from a file - unit-testing

I have a test case where I need to mock downloading an image. The issue is when I mock this download function, it makes the other functions in that file undefined, but I also need to call the other functions in the test as they originally exist without mocking.
Is there a way to mock only one function from App.Functions in the example below and keep the rest of the functions working the same?
The code looks like this for setting up the mock:
setup_with_mocks(
[
{App.Functions, [], [download_file: fn _url -> :ok end]}
],
context
)

Seems that you are using Mock (https://hexdocs.pm/mock/Mock.html). In that case you can use the passthrough option:
test_with_mock "test_name", App.Functions, [:passthrough], [download_file: fn _url -> :ok end] do
end
I don't know if the option is available also for setup_with_mocks.
More info here: https://github.com/jjh42/mock#passthrough---partial-mocking-of-a-module

Sometimes when you encounter difficulty in mocking functions for testing it can indicate an organizational problem in your code, e.g. a violation of the single-responsibility-principle. Pondering things like this starts to venture into more philosophical territory (which Stackoverflow is not geared towards), but generally it's helpful to isolate your modules in a way that is compatible with testing -- some of the common code/repo organizational patterns fall into place more easily when giving due consideration to facilitating testing.
As already noted, Mock allows the passthrough option.
The Mox package does not have a viable solution to this particular use case -- even its skipping-optional-callbacks option does not really fit the bill.
Another option is to go the more manual route: pass an opt (or read one out of the Application config) that can be overridden at runtime to facilitate testing. This tactic smells to me a bit like Javascript's heavy reliance on passing callback functions, but it can work in a pinch, e.g. something like:
def download(url, opts \\ []) do
http_client = Keyword.get(opts, :client, HTTPoison)
http_client.get(url)
end
# OR
def download(url) do
http_client = Application.get_env(:myapp, :http_client, HTTPoison)
http_client.get(url)
end
Then in your tests:
test "download a file" do
assert {:ok, _} = MyApp.download("http://example", client: HttpClientMock)
end
# OR...
setup do
starting_value = Application.get_env(:myapp, :http_client)
on_exit(fn ->
Application.put_env(:myapp, :http_client, starting_value)
end)
end
test "download a file" do
Application.put_env(:myapp, :http_client, ClientMock)
# ...
end
This has the disadvantage of punting compile-time errors into runtime (which might be a worthwhile tradeoff to achieve test coverage), and this approach can become disorganized, so use with care.
Generally, I've found Mox's approach to rely on behaviours/callbacks to lead to cleaner tests and cleaner code, but your mileage and use-cases may vary.

Related

Writing unit test for make handler function in Go-kit

My problem is specific to Go-kit and how to organize code within.
I'm trying to write a unit test for the following function:
func MakeHandler(svc Service, logger kitlog.Logger) http.Handler {
orderHandler := kithttptransport.NewServer(
makeOrderEndpoint(svc),
decodeRequest,
encodeResponse,
)
r := mux.NewRouter()
r.Handle("/api/v1/order/", orderHandler).Methods("GET")
return r
}
What would be the correct way of writing a proper unit test? I have seen examples such as the following:
sMock := &ServiceMock{}
h := MakeHandler(sMock, log.NewNopLogger())
r := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/v1/order/", bytes.NewBuffer([]byte("{}")))
h.ServeHTTP(r, req)
And then testing the body and headers of the request. But this doesn't seem like a proper unit test, as calls other parts of the code (orderHandler). Is it possible to just validate what's returned from MakeHandler() instead of during a request?
TL;DR: Yes, that test is in the right direction. You shouldn't try to test the
internals of the returned handler since that third party package may change in ways you didn't expect in the future.
Is it possible to just validate what's returned from MakeHandler() instead of
during a request?
Not in a good way. MakeHandler() returns an interface and ideally you'd use
just the interface methods in your tests.
You could look at the docs of the type returned by mux.NewRouter() to see if
there are any fields or methods in the concrete type that can give you the
information, but that can turn out to be a pain - both for understanding the
tests (one more rarely used type to learn about) and due to how future
modifications to the mux package may affect your code without breaking the
tests.
What would be the correct way of writing a proper unit test?
Your example is actually in the right direction. When testing MakeHandler(),
you're testing that the handler returned by it is able to handle all the paths
and calls the correct handler for each path. So you need to call the
ServeHTTP() method, let it do its thing and then test to see it worked
correctly. Only introspecting the handler does not guarantee correctness during
actual usage.
You may need to make actually valid requests though so you're able to understand
which handler was called based on the response body or header. That should
bring the test to a quite reasonable state. (I think you already have that)
Similarly, I'd add a basic sub test for each route that's added in the future.
Detailed handler tests can be written in separate funcs.

Unit testing side effects in Elixir

I'm writing a unit test for a function that calls out to module as part of a side effect of invoking it:
defmodule HeimdallrWeb.VerifyController do
use HeimdallrWeb, :controller
def verify(conn, _params) do
[forwarded_host | _tail] = get_req_header(conn, "x-forwarded-host")
case is_preview_page?(forwarded_host) do
{:ok, false} ->
conn |> send_resp(200, "")
{:ok, %Heimdallr.Commits.Commit{} = commit} ->
Heimdallr.Commits.touch_commit(commit)
conn |> send_resp(200, "")
{:not_found, _reason} ->
conn |> send_resp(200, "")
end
end
end
The side effect is triggered from the line Heimdallr.Commits.touch_commit(commit).
A few questions about this:
Should my unit test be concerned with testing the effects of the touch_commit method.
If so, should I think about passing in a generic "touch" function to verify method to make it easier to test. This might be difficult due to the nature of Phoenix / Elixirs routing system, I haven't investigated.
If I was using Rails / Ruby / Rspec then I'd set an expectation that a class level method would be called on the HeimdallrCommits module.
My concern and reason for writing the test is that in the future I may accidentally remove the functionality that is touching a commit by deleting or commenting out the line etc.
I would say 1: No. And that is to keep the complexity low in your test. You only want to test (whatever it is you want to test) in a method, the rest should be mocked ignored. What you could do is verify what your method have invoked touch_commit - should be part of a good mocking framework. Those are my 5 cent, sorry to say that I am not familiar with phoenix/elixir so I can't give you any working examples. Like the verify method i Mockito or Moq is what I am thinking of..

Mocking external struct dependencies in golang

I am having a hard time figuring out an idiomatic way of writing testable code in golang. I understand the importance of interfaces and their use in testing, but I haven't figured out how to mock/test external struct dependencies.
As an example, I have written the following which simulates a wrapper for creating a pull request on GitHub.
type GitHubService interface {
}
type gitHubService struct {
CreatePullRequest(...) (PullRequest,error)
}
func (s gitHubService) CreatePullRequest(...) (PullRequest,error) {
tp := github.BasicAuthTransport{
Username: strings.TrimSpace(/*.....*/),
Password: strings.TrimSpace(/*.....*/),
}
client := github.NewClient(tp.Client())
pr,err := client.Repositories.CreatePullRequest(...)
...
}
func TestPullRequest(t *testing.T) {
service := gitHubService{}
pr,err := service.CreatePullRequest(...)
...
}
If I was writing a unit test for GitHubService.CreatePullRequest(...) I would want to mock the call to client.Repositories.CreatePullRequest(...) and probably even github.NewClient(...) to return mock implementations that I can control.
With tools such as gomock it seems that you are out of luck with structs and package functions.
What is the idiomatic way to handle this? I am very familiary with Inversion of Control and the different patterns such as Dependency Injection and Service Locator, but I have heard countless times that this is not idiomatic.
One important design feature of Go is decoupling (Watch this great talk from Bill Kennedy about that topic). Inside your method there are some dependencies, which could be decoupled. This coupled method makes it not really testable.
Thing you should refactor:
tp := github.BasicAuthTransport: you should not initialize the authorization inside of your method. It should move into your gitHubService as a parameter. Inside your method call you can access ist via s.tp. You could also make it an input parameter of the method.
github.NewClient() and client.Repositories.CreatePullRequest(...) just read about the golang best practices from Peter Bourgon Make dependencies explicit!. The alternative is to create an interface, which contains all the called functions. This interface should be an input to your method.
After your code is decoupled you can mock everything very easy. If you use interfaces as an input you can just create a mock struct, which implements the interface. If you make the dependencies explicit you can overwrite them. In the last case the code for storing the values of the calls is not so clean, but it also works. The idiomatic go way is to use interfaces.
I had a similar problem and looks like, the only option you have is to have another layer in between which would call your "unmockable" clients.
For e.g. for mocking the govmi clients (vmware clients sdk for golang), I had to have a "myCustomClient" having interfaces and structs to make calls to govmi.Client.AnyMethod..
I could then generate mocks for "myCustomClient".
mockgen -source myCustomClient.go -package myPackage -destination myCustomClientMock.go
You can install it by: got get github.com/golang/mock

Mocking a dependency in Node

I'm in the process of learning Node.js and am wondering about how people mock dependencies in their modules when unit testing.
For example:
I have a module that abstracts my MongoDB calls. A module that uses this module may start out something like this.
var myMongo = require("MyMongoModule");
// insert rest of the module here.
I want to ensure I test such a module in isolation while also ensuring that my tests don't insert records/documents into Mongo.
Is there a module/package that I can use that proxies require() so I can inject in my own mocks? How do other's typically address this issue?
You can use a dependency injection library like nCore
To be honest, the hard part of this is actually mocking out the mongoDB API, which is complex and non trivial. I estimate it would take about a week to mock out most of the mongo API I use so I just test againts the a local mongodb database on my machine (which is always in a weird state)
Then with nCore specific syntax
// myModule.js
module.exports = {
myMethod: function () {
this.mongo.doStuff(...)
},
expose: ["myMethod"]
};
// test-myModule.js
var module = require("myModule")
module.mongo = mongoMock
assert(module.myMethod() === ...)
After reviewing Ryanos's suggestion as well as the Horaa package on npm, I discovered this thread on the Google Group that pointed me towards Sandboxed-Module.
Sandboxed-Module allows me to inject/override require() without me having to expose such dependencies for my unit tests.
I'm still up for other suggestions; however, Sandboxed-Module appears to fit my needs at the moment.
You easily mock require by using "a": https://npmjs.org/package/a
e.g. need to mock require('./foo') in unit test:
var fakeFoo = {};
var expectRequire = require('a').expectRequire;
expectRequire('./foo).return(fakeFoo);
//in sut:
var foo = require('./foo); //returns fakeFoo
Overwriting require to inject your mocks is a possible solution. However, I concur in Raynos' opinion:
I personally find the methodology of overwriting require on a file by file basis an "ugly hack" and prefer to go for proper DI. It is however optimum for mocking one or two modules on an existing code base without rewriting code for DI support.
To use proper dependency injection not only saves you an "ugly hack" but also allows you to apply additional use cases apart from injecting mocks. In production you may e.g. usually instantiate connections over http and in certain circumstances inject a different implementation to establish a connection over VPN.
If you want to look for a dependency injection container read this excellent article and check out Fire Up! which I implemented.

Unit testing functions with side effects?

Let's say you're writing a function to check if a page was reached by the appropriate URL. The page has a "canonical" stub - for example, while a page could be reached at stackoverflow.com/questions/123, we would prefer (for SEO reasons) to redirect it to stackoverflow.com/questions/123/how-do-i-move-the-turtle-in-logo - and the actual redirect is safely contained in its own method (eg. redirectPage($url)), but how do you properly test the function which calls it?
For example, take the following function:
function checkStub($questionId, $baseUrl, $stub) {
canonicalStub = model->getStub($questionId);
if ($stub != $canonicalStub) {
redirectPage($baseUrl . $canonicalStub);
}
}
If you were to unit test the checkStub() function, wouldn't the redirect get in the way?
This is part of a larger problem where certain functions seem to get too big and leave the realm of unit testing and into the world of integration testing. My mind immediately thinks of routers and controllers as having these sorts of problems, as testing them necessarily leads to the generation of pages rather than being confined to just their own function.
Do I just fail at unit testing?
You say...
This is part of a larger problem where certain functions seem to get too big and leave the realm of unit testing and into the world of integration testing
I think this is why unit testing is (1) hard and (2) leads to code that doesn't crumble under its own weight. You have to be meticulous about breaking all of your dependencies or you end up with unit tests == integration tests.
In your example, you would inject a redirector as a dependency. You use a mock, double or spy. Then you do the tests as #atk lays out. Sometimes it's not worth it. More often it forces you to write better code. And it's hard to do without an IOC container.
This is an old question, but I think this answer is relevant. #Rob states that you would inject a redirector as a dependency - and sure, this works. However, your problem is that you don't have a good separation of concerns.
You need to make your functions as atomic as possible, and then compose larger functionality using the granular functions you've created. You wrote this:
function checkStub($questionId, $baseUrl, $stub) {
canonicalStub = model->getStub($questionId);
if ($stub != $canonicalStub) {
redirectPage($baseUrl . $canonicalStub);
}
}
I'd write this:
function checkStubEquality($stub1, $stub2) {
return $stub1 == $stub2;
}
canonicalStub = model->getStub($questionId);
if (!checkStubEquality(canonicalStub, $stub)) redirectPage($baseUrl . $canonicalStub);
It sounds like you just have another test case. You need to check that the stub is identified correctly as a stub with both positive and negative testing, and you need to check that the page to which you are redirected is correct.
Or do I totally misunderstand the question?