Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I’ve used the following logger lib for our program.
We have create unit tests and we need to provide mock for version 0.4.0
https://github.com/go-logr/logr/blob/v0.4.0/logr.go#L148
This is how we mocked the functions which works as expected
type testLog struct {
msg string
key string
value string
}
func (log *testLog) Enabled() bool {
return true
}
func (log *testLog) Info(msg string, keysAndValues ...interface{}) {
log.msg = msg
log.key = keysAndValues[0].(string)
log.value = keysAndValues[1].(string)
}
func (log *testLog) Error(err error, msg string, keysAndValues ...interface{}) {
}
func (log *testLog) V(level int) logr.Logger {
return &testLog{}
}
func (log *testLog) WithValues(keysAndValues ...interface{}) logr.Logger {
return &testLog{}
}
func (log *testLog) WithName(name string) logr.Logger {
return &testLog{}
}
Now we need to upgrade to version 1.2.0
And the implementation is changed, there is no interface.
My question is how should I mock the logger with the new version ?
See this link with the followed functions
https://github.com/go-logr/logr/blob/v1.2.2/logr.go#L230
My question is how should I mock the logger with the new version ?
You cannot. Come up with a non mock-based testing strategy.
Related
Let's say I have a package with the following code:
package paths
type FilePath struct {
PathA string
}
func (c FilePath) GetPathA() string {
if err := PathExists(PathA); err != nil {
return ""
}
return PathA + "foo"
}
func PathExists(p string) error {
// call os and file methods
return err
}
How do I mock out the PathExists dependency to test FilePath? Also, method PathExists is being used by a lot of other packages as well. (I am open to suggestions of refactoring this to make it test friendly, keeping the following pointers in mind)
I have come across a few different approaches but none of them seems intuitive or idiomatic to me.
Have a global variable PE := PathExists in the package; in GetPathA, call err := PE(PathA) and in the test overwrite PE with a mock method.
Issue: If test package is something like paths_test, I will have to export PE which allows clients of the package to overwrite it as well.
Make PathExists a field of FilePath and mock the field in test.
Issue: Clients when using the package, will have to initialize PathExists field, or I provide a constructor of the form NewFilePath(PathtA string) which initializes the fields for me. In the actual use case there are a lot of fields, hence this approach fails as well.
Use an interface and embed it within the struct. When client uses it initialize with the actual method and for test mock it.
type PathExistser interface{
PathExists(p string) error
}
type FilePath struct{
PathA string
PathExister
}
type Actual struct{}
func (a Actual) PathExists(p string) error {
return PathExists(p)
}
Issue: Client again needs to provide the right implementation of the interface.
I have learnt of few more approaches doing something simimlar to the above options, such as make the method PathExists an argument for GetPathA, etc. All have the same concerns. Basically, I don't want the users of this package to have to figure out what should be the right input parameter to make sure the struct works as expected. Neither do I want the users to overwrite the behaviour PathExists.
This seems like a very straightforward problem and I seem to be missing something very funamental about go testing or mocking. Any help would be appreciated, thanks.
Method names are just for example. In reality GetPathA or PathExists would be way more complex.
To address the issue from your 1. approach, you can use an internal package which you'll then be able to import in paths_test but clients of your package won't be.
package paths
import (
// ...
"<your_module_path>/internal/osutil"
)
func PathExists(p string) error {
return osutil.PathExists(p)
}
package osutil
var PathExists = func(p string) error {
// call os and file methods
return err
}
// Use a mutex to make sure that if you have
// multiple tests using mockPathExists and running
// in parallel you avoid the possiblity of a data race.
//
// NOTE that the mutex is only useful if *all* of your tests
// use MockPathExists. If only some do while others don't but
// still directly or indirectly cause the paths.PathExists
// function to be invoked then you still can run into a data
// race problem.
var mu sync.Mutex
func MockPathExists(mock func(p string) error) (unmock func()) {
mu.Lock()
original := PathExists
PathExists = mock
return func() {
PathExists = original
mu.Unlock()
}
}
package paths_test
import (
// ...
"<your_module_path>/internal/osutil"
)
func TestPathExists(t *testing.T) {
unmock := osutil.MockPathExists(myPathExistsMockImpl)
defer unmock()
// do your test
}
This question already has answers here:
How to mock external dependencies in tests? [duplicate]
(1 answer)
How to mock specific methods but not all of them in Rust?
(2 answers)
How can I test stdin and stdout?
(1 answer)
Is there a way of detecting whether code is being called from tests in Rust?
(1 answer)
What is the proper way to use the `cfg!` macro to choose between multiple implementations?
(1 answer)
Closed 2 years ago.
Iam current building a application which heavy relies on File IO, so obviously lots of parts of my code have File::open(file).
Doing some integration tests are ok, I can easily set folders to load file and scenarios needed for it.
The problem comes whatever I want to unit tests, and code branches. I know there is lots of mocking libraries out there that claim to mocks, but i feel my biggest problem is code design itself.
Let's say for instance, I would do the same code in any object oriented language (java in the example), i could write some interfaces, and on tests simple override the default behavior I want to mock, set the a fake ClientRepository, whatever reimplemented wih a fixed return, or use some mocking framework, like mockito.
public interface ClientRepository {
Client getClient(int id)
}
public class ClientRepositoryDB {
private ClientRepository repository;
//getters and setters
public Client getClientById(int id) {
Client client = repository.getClient(id);
//Some data manipulation and validation
}
}
But i couldn`t manage to get the same results in rust, since we endup mixing data with behavior.
On the RefCell documentation, there is a similar example with the one I gave on java. Some of answers points to traits, clojures, conditional compiliation
We might come with some scenarios in test, first one a public function in some mod.rs
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SomeData {
pub name: Option<String>,
pub address: Option<String>,
}
pub fn get_some_data(file_path: PathBuf) -> Option<SomeData> {
let mut contents = String::new();
match File::open(file_path) {
Ok(mut file) => {
match file.read_to_string(&mut contents) {
Ok(result) => result,
Err(_err) => panic!(
panic!("Problem reading file")
),
};
}
Err(err) => panic!("File not find"),
}
// using serde for operate on data output
let some_data: SomeData = match serde_json::from_str(&contents) {
Ok(some_data) => some_data,
Err(err) => panic!(
"An error occour when parsing: {:?}",
err
),
};
//we might do some checks or whatever here
Some(some_data) or None
}
mod test {
use super::*;
#[test]
fn test_if_scenario_a_happen() -> std::io::Result<()> {
//tied with File::open
let some_data = get_some_data(PathBuf::new);
assert!(result.is_some());
Ok(())
}
#[test]
fn test_if_scenario_b_happen() -> std::io::Result<()> {
//We might need to write two files, and we want to test is the logic, not the file loading itself
let some_data = get_some_data(PathBuf::new);
assert!(result.is_none());
Ok(())
}
}
The second the same function becoming a trait and some struct implement it.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SomeData {
pub name: Option<String>,
pub address: Option<String>,
}
trait GetSomeData {
fn get_some_data(&self, file_path: PathBuf) -> Option<SomeData>;
}
pub struct SomeDataService {}
impl GetSomeData for SomeDataService {
fn get_some_data(&self, file_path: PathBuf) -> Option<SomeData> {
let mut contents = String::new();
match File::open(file_path) {
Ok(mut file) => {
match file.read_to_string(&mut contents) {
Ok(result) => result,
Err(_err) => panic!("Problem reading file"),
};
}
Err(err) => panic!("File not find"),
}
// using serde for operate on data output
let some_data: SomeData = match serde_json::from_str(&contents) {
Ok(some_data) => some_data,
Err(err) => panic!("An error occour when parsing: {:?}", err),
};
//we might do some checks or whatever here
Some(some_data) or None
}
}
impl SomeDataService {
pub fn do_something_with_data(&self) -> Option<SomeData> {
self.get_some_data(PathBuf::new())
}
}
mod test {
use super::*;
#[test]
fn test_if_scenario_a_happen() -> std::io::Result<()> {
//tied with File::open
let service = SomeDataService{}
let some_data = service.do_something_with_data(PathBuf::new);
assert!(result.is_some());
Ok(())
}
}
On both examples, we have a hard time unit testing it, since we tied with File::open, and surely, this might be extend to any non-deterministic function, like time, db connection, etc.
How would you design this or any similar code to make easier to unit testing and better design?
How would you design this or any similar code to make easier to unit testing and better design?
One way is to make get_some_data() generic over the input stream. The std::io module defines a Read trait for all things you can read from, so it could look like this (untested):
use std::io::Read;
pub fn get_some_data(mut input: impl Read) -> Option<SomeData> {
let mut contents = String::new();
input.read_to_string(&mut contents).unwrap();
...
}
You'd call get_some_data() with the input, e.g. get_some_data(File::open(file_name).unwrap()) or get_some_data(&mut io::stdin::lock()), etc. When testing, you can prepare the input in a string and call it as get_some_data(io::Cursor::new(prepared_data)).
As for the trait example, I think you misunderstood how to apply the pattern to your code. You're supposed to use the trait to decouple getting the data from processing the data, sort of how you'd use an interface in Java. The get_some_data() function would receive an object known to implement the trait.
Code more similar to what you'd find in an OO language might choose to use a trait object:
trait ProvideData {
fn get_data(&self) -> String
}
struct FileData(PathBuf);
impl ProvideData for FileData {
fn get_data(&self) -> String {
std::fs::read(self.0).unwrap()
}
}
pub fn get_some_data(data_provider: &dyn ProvideData) -> Option<SomeData> {
let contents = data_provider.get_data();
...
}
// normal invocation:
// let some_data = get_some_data(&FileData("file name".into()));
In test you'd just create a different implementation of the trait - for example:
#[cfg(test)]
mod test {
struct StaticData(&'static str);
impl ProvideData for StaticData {
fn get_data(&self) -> String {
self.0.to_string()
}
}
#[test]
fn test_something() {
let some_data = get_some_data(StaticData("foo bar"));
assert!(...);
}
}
First of all, I would like to thank #user4815162342 for enlightenment of traits. Using his answer as base, i solve with my own solution for the problem.
First, I build as mention, traits to better design my code:
trait ProvideData {
fn get_data(&self) -> String
}
But I had some problems, since there were tons of bad design code, and lots code I had to mock before run the test, something like the below code.
pub fn some_function() -> Result<()> {
let some_data1 = some_non_deterministic_function(PathBuf::new())?;
let some_data2 = some_non_deterministic_function_2(some_data1);
match some_data2 {
Ok(ok) => Ok(()),
Err(err) => panic!("something went wrong"),
}
}
I would need to change almost all functions signatures to accept Fn, this would not only change most my code, but will actually make it hard to read, since most of it I was changing for testing purpose only.
pub fn some_function(func1: Box<dyn ProvideData>, func2: Box<dyn SomeOtherFunction>) -> Result<()> {
let some_data1 = func1(PathBuf::new())?;
let some_data2 = func2(some_data1);
match some_data2 {
Ok(ok) => Ok(()),
Err(err) => panic!("something went wrong"),
}
}
Reading a little more deep the rust documentation, I slight changed the implementation.
Change almost all my code to use traits and structs ( Lots of code were public functions )
trait ProvideData {
fn get_data(&self) -> String;
}
struct FileData(PathBuf);
impl ProvideData for FileData {
fn get_data(&self) -> String {
String::from(format!("Pretend there is something going on here with file {}", self.0.to_path_buf().display()))
}
}
Add a new functions for default implementation in the structs, and add constructor with default implementation using dynamic dispatch functions.
struct SomeData(Box<dyn ProvideData>);
impl SomeData {
pub fn new() -> SomeData {
let file_data = FileData(PathBuf::new());
SomeData {
0: Box::new(file_data)
}
}
pub fn get_some_data(&self) -> Option<String> {
let contents = self.0.get_data();
Some(contents)
}
}
Since the constructor is private, we prevent user from injecting code, and we can freely change the internal implementation for testing purpose, and the integration tests keep running smooth.
fn main() {
//When the user call this function, it would no know that there is multiple implementations for it.
let some_data = SomeData::new();
assert_eq!(Some(String::from("Pretend there is something going on here with file ")),some_data.get_some_data());
println!("HEY WE CHANGE THE INJECT WITHOUT USER INTERATION");
}
And finally, since we test inside the declaration scope, we might change the injection even if is private:
mod test {
use super::*;
struct MockProvider();
impl ProvideData for MockProvider {
fn get_data(&self) -> String {
String::from("Mocked data")
}
}
#[test]
fn test_internal_data() {
let some_data = SomeData(Box::from(MockProvider()));
assert_eq!(Some(String::from("Mocked data")), some_data.get_some_data())
}
#[test]
fn test_ne_internal_data() {
let some_data = SomeData(Box::from(MockProvider()));
assert_ne!(Some(String::from("Not the expected data")), some_data.get_some_data())
}
}
The result code can be seem in the rust playground, hope this help user to design their code.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=62348977502accfed55fa4600d149bcd
This question already has answers here:
How to mock external dependencies in tests? [duplicate]
(1 answer)
How to mock specific methods but not all of them in Rust?
(2 answers)
How can I test stdin and stdout?
(1 answer)
Is there a way of detecting whether code is being called from tests in Rust?
(1 answer)
What is the proper way to use the `cfg!` macro to choose between multiple implementations?
(1 answer)
Closed 2 years ago.
I'm trying to run unit tests on a function reducer . reducer takes in a struct State and an enum Action and returns a new struct State . When the action is Action::Status , I want the function state.status_function to be called on state. I'm having trouble testing that a mock function I pass into test_status is called with state. Does anyone know what I'm getting wrong in the code below?
fn test_status() {
let mut status_mock_called: bool;
let state = State {
status_function: Box::new(|state: State| {
status_mock_called = true;
return state;
}),
};
assert_eq!(root_reducer(state, Action::Status), state);
assert!(status_mock_called);
}
Outputs the error:
`(dyn std::ops::Fn(State) -> State + 'static)` doesn't implement `std::fmt::Debug`
How can I modify a rust variable from inside a function?
Here is the state struct in case it's relevant:
#[derive(Debug, Eq, PartialEq)]
struct State {
status_function: Box<dyn Fn(State) -> State>,
}
And here is the reducer:
fn root_reducer(state: State, action: Action) -> State {
match action {
Action::Status => (state.status_function)(state),
}
}
TL;DR: mocked method accepts closure. I wonder how to create custom matcher (https://godoc.org/github.com/golang/mock/gomock#Matcher): closure itself in turn is working with private structure - meaning I can't even call the closure in my test to check it against expectations.
I'm working on a small app using Slack API with help of nlopes/slack (https://github.com/nlopes/slack).
For testing, I'm mocking nlopes/slack with gomock. For that I've created interface
type slackAPI interface {
OpenConversation(*slack.OpenConversationParameters) (*slack.Channel, bool, bool, error)
PostMessage(channelID string, options ...slack.MsgOption) (string, string, error)
GetUserByEmail(email string) (*slack.User, error)
}
I have no problem testing OpenConversation or GetUserByEmail, e.g.
slackAPIClient.
EXPECT().
GetUserByEmail("some#email.com").
Return(slackUserJohndoe, nil).
Times(1)
Things get more complicated when it comes to PostMessage. In main code the call looks like
_, _, err := slackAPIClient.PostMessage(channel.ID, slack.MsgOptionText(message, false))
And slack.MsgOptionText (from nlopes/slack) is actually returning closure:
func MsgOptionText(text string, escape bool) MsgOption {
return func(config *sendConfig) error {
if escape {
text = slackutilsx.EscapeMessage(text)
}
config.values.Add("text", text)
return nil
}
}
Since method is accepting closure, I need to create custom gomock matcher (https://godoc.org/github.com/golang/mock/gomock#Matcher). Custom matcher itself is not a problem, it would look something like
type higherOrderFunctionEqMatcher struct {
x interface{}
}
func (e hofEqMatcher) Matches(x interface{}) bool {
//return m.x == x
return true
}
func (e hofEqMatcher) String(x interface{}) string {
return fmt.Sprintf("is equal %v", e.x)
}
However, since MsgOptionText uses nlopes/slack private structure sendConfig, I wonder how can I even work with that in scope of my test to check equality to expectations.
How should I tackle such problem?
Bearing in mind that
in Golang you can't compare functions
in this precise case I can't do indirect test by calling closure itself (since it's using private 3rd party lib's structure as an argument)
the solution I've found is to mock slack.MsgOptionText(message, false), which in turn returns closure for PostMessage(channelID string, options ...slack.MsgOption):
type slackMsgCreator interface {
MsgOptionText(string, bool) slack.MsgOption
}
type slackMsgCreatorInst struct{}
func (s slackMsgCreatorInst) MsgOptionText(text string, escape bool) slack.MsgOption {
return slack.MsgOptionText(text, escape)
}
...
slackMsgCreator.
EXPECT().
MsgOptionText("Dear John Doe, message goes here", false).
Return(slack.MsgOptionText("Dear John Doe, message goes here", false)).
Times(1)
And, as for PostMessage - as was advised in comments, the only thing that I could check is that closure is not nil:
slackAPIClient.
EXPECT().
PostMessage("ABCDE", Not(Nil())).
AnyTimes()
I have a struct which implements Deserialize and uses the serde(deserialize_with) on a field:
#[derive(Debug, Deserialize)]
struct Record {
name: String,
#[serde(deserialize_with = "deserialize_numeric_bool")]
is_active: bool,
}
The implementation of deserialize_numeric_bool deserializes a string "0" or "1" to the corresponding boolean value:
pub fn deserialize_numeric_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
where D: Deserializer<'de>
{
struct NumericBoolVisitor;
impl<'de> Visitor<'de> for NumericBoolVisitor {
type Value = bool;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("either 0 or 1")
}
fn visit_u64<E>(self, value: u64) -> Result<bool, E>
where E: DeserializeError
{
match value {
0 => Ok(false),
1 => Ok(true),
_ => Err(E::custom(format!("invalid bool: {}", value))),
}
}
}
deserializer.deserialize_u64(NumericBoolVisitor)
}
(I appreciate comments about code improvements)
I'd like to write unit tests for deserialization functions like deserialize_numeric_bool. Of course, my friendly search box revealed the serde_test crate and a documentation page about unit-testing.
But these resources couldn't help me in my case, as the crate tests a structure directly implementing Deserialize.
One idea I had was to create a newtype which only contains the output of my deserialize functions and test it with it. But this looks like a unnecessary indirection to me.
#[derive(Deserialize)]
NumericBool {
#[serde(deserialize_with = "deserialize_numeric_bool")]
value: bool
};
How do I write idiomatic tests for it?
My current solution uses only structures already provided by serde.
In my use case, I only wanted to test that a given string will deserialize successfully into a bool or has a certain error. The serde::de::value provides simple deserializers for fundamental data types, for example U64Deserializer which holds a u64. It also has an Error struct which provides a minimal representation for the Error traits – ready to be used for mocking errors.
My tests look currently like that: I mock the input with a deserializer and pass it to my function under test. I like that I don't need an indirection there and that I have no additional dependencies. It is not as nice as the assert_tokens* provided serde_test, as it needs the error struct and feels less polished. But for my case, where only a single value is deserialized, it fulfills my needs.
use serde::de::IntoDeserializer;
use serde::de::value::{U64Deserializer, StrDeserializer, Error as ValueError};
#[test]
fn test_numeric_true() {
let deserializer: U64Deserializer<ValueError> = 1u64.into_deserializer();
assert_eq!(numeric_bool(deserializer), Ok(true));
}
#[test]
fn test_numeric_false() {
let deserializer: U64Deserializer<ValueError> = 0u64.into_deserializer();
assert_eq!(numeric_bool(deserializer), Ok(false));
}
#[test]
fn test_numeric_invalid_number() {
let deserializer: U64Deserializer<ValueError> = 2u64.into_deserializer();
let error = numeric_bool(deserializer).unwrap_err();
assert_eq!(error.description(), "invalid bool: 2");
}
#[test]
fn test_numeric_empty() {
let deserializer: StrDeserializer<ValueError> = "".into_deserializer();
let error = numeric_bool(deserializer).unwrap_err();
assert_eq!(error.description(), "invalid type: string \"\", expected either 0 or 1");
}
I hope that it helps other folks too or inspire other people to find a more polished version.
I've come across this question several times while trying to solve a similar problem recently. For future readers, pixunil's answer is nice, straightforward, and works well. However, I'd like to provide a solution using serde_test as the unit testing documentation mentions.
I researched how serde_test is used across a few crates that I found via its reverse dependencies on lib.rs. Several of them define small structs or enums for testing deserialization or serialization as you mentioned in your original post. I suppose doing so is idiomatic when testing would be too verbose otherwise.
Here's a few examples; this is a non-exhaustive list:
Example from time
Another example from time
Example from slab (tokio)
Example from bitcoin_hashes
Example from uuid
Example from euclid
Anyway, let's say I have a function to deserialize a bool from a u8 and another function that serializes a bool to a u8.
use serde::{
de::{Error as DeError, Unexpected},
Deserialize, Deserializer, Serialize, Serializer,
};
fn bool_from_int<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
match u8::deserialize(deserializer)? {
0 => Ok(false),
1 => Ok(true),
wrong => Err(DeError::invalid_value(
Unexpected::Unsigned(wrong.into()),
&"zero or one",
)),
}
}
#[inline]
fn bool_to_int<S>(a_bool: &bool, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if *a_bool {
serializer.serialize_u8(1)
} else {
serializer.serialize_u8(0)
}
}
I can test those functions by defining a struct in my test module. This allows constraining the tests to those functions specifically instead of ser/deserializing a larger object.
#[cfg(test)]
mod tests {
use super::{bool_from_int, bool_to_int};
use serde::{Deserialize, Serialize};
use serde_test::{assert_de_tokens_error, assert_tokens, Token};
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(transparent)]
struct BoolTest {
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
a_bool: bool,
}
const TEST_TRUE: BoolTest = BoolTest { a_bool: true };
const TEST_FALSE: BoolTest = BoolTest { a_bool: false };
#[test]
fn test_true() {
assert_tokens(&TEST_TRUE, &[Token::U8(1)])
}
#[test]
fn test_false() {
assert_tokens(&TEST_FALSE, &[Token::U8(0)])
}
#[test]
fn test_de_error() {
assert_de_tokens_error::<BoolTest>(
&[Token::U8(14)],
"invalid value: integer `14`, expected zero or one",
)
}
}
BoolTest is within the tests module which is gated by #[cfg(test)] as per usual. This means that BoolTest is only compiled for tests rather than adding bloat. I'm not a Rust expert, but I think this is a good alternative if a programmer wishes to use serde_test as a harness.